Add new test framework.

This commit is contained in:
WenhaiLin 2015-04-03 11:54:39 +08:00
parent fdba25cdde
commit 6f47006324
9 changed files with 999 additions and 698 deletions

View File

@ -1,6 +1,6 @@
/****************************************************************************
Copyright (c) 2013 cocos2d-x.org
Copyright (c) 2013-2014 Chukong Technologies Inc.
Copyright (c) 2013-2015 Chukong Technologies Inc.
http://www.cocos2d-x.org
@ -33,13 +33,12 @@
USING_NS_CC;
AppDelegate::AppDelegate()
:_curTest(nullptr)
{
}
AppDelegate::~AppDelegate()
{
// SimpleAudioEngine::end();
//SimpleAudioEngine::end();
cocostudio::ArmatureDataManager::destroyInstance();
}
@ -73,7 +72,6 @@ bool AppDelegate::applicationDidFinishLaunching()
director->setAnimationInterval(1.0 / 60);
auto screenSize = glview->getFrameSize();
auto designSize = Size(480, 320);
auto fileUtils = FileUtils::getInstance();
@ -103,7 +101,6 @@ bool AppDelegate::applicationDidFinishLaunching()
searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UICheckBox");
searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIImageView");
searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILabel");
// searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILabelAtlas");
searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILabelBMFont");
searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/BackgroundImage");
searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/Color");
@ -139,12 +136,10 @@ bool AppDelegate::applicationDidFinishLaunching()
searchPaths.push_back("ccs-res/scenetest/UIComponentTest");
searchPaths.push_back("ccs-res/scenetest/TriggerTest");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIButton");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UICheckBox");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIImageView");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILabel");
// searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILabelAtlas");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILabelBMFont");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/BackgroundImage");
searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/Color");
@ -165,7 +160,6 @@ bool AppDelegate::applicationDidFinishLaunching()
searchPaths.push_back("ccs-res/cocosui/CustomTest/CustomWidgetCallbackBindTest");
searchPaths.push_back("ActionTimeline");
searchPaths.push_back("ccs-res/armature");
}
fileUtils->setSearchPaths(searchPaths);
@ -177,22 +171,7 @@ bool AppDelegate::applicationDidFinishLaunching()
glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::SHOW_ALL);
#endif
auto scene = Scene::create();
auto layer = new (std::nothrow) TestController();
layer->autorelease();
layer->addConsoleAutoTest();
scene->addChild(layer);
director->runWithScene(scene);
// Enable Remote Console
auto console = director->getConsole();
console->listenOnTCP(5678);
Configuration *conf = Configuration::getInstance();
bool isAutoRun = conf->getValue("cocos2d.x.testcpp.autorun", Value(false)).asBool();
if(isAutoRun)
{
layer->startAutoRun();
}
_testController = TestController::getInstance();
return true;
}
@ -200,21 +179,13 @@ bool AppDelegate::applicationDidFinishLaunching()
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground()
{
_testController->onEnterBackground();
Director::getInstance()->stopAnimation();
}
// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
_testController->onEnterForeground();
Director::getInstance()->startAnimation();
}
void AppDelegate::setCurrentTest(BaseTest* curTest)
{
_curTest = curTest;
}
BaseTest* AppDelegate::getCurrentTest()
{
return _curTest;
}

View File

@ -27,7 +27,8 @@
#define _APP_DELEGATE_H_
#include "cocos2d.h"
#include "BaseTest.h"
class TestController;
/**
@brief The cocos2d Application.
@ -60,10 +61,8 @@ public:
*/
virtual void applicationWillEnterForeground();
BaseTest* getCurrentTest();
void setCurrentTest(BaseTest* curTest);
private:
BaseTest* _curTest;
TestController* _testController;
};
#endif // _APP_DELEGATE_H_

View File

@ -1,5 +1,5 @@
/****************************************************************************
Copyright (c) 2013-2014 Chukong Technologies Inc.
Copyright (c) 2013-2015 Chukong Technologies Inc.
http://www.cocos2d-x.org
@ -23,79 +23,381 @@
****************************************************************************/
#include "BaseTest.h"
#include "VisibleRect.h"
#include "testResource.h"
#include "AppDelegate.h"
#include "controller.h"
USING_NS_CC;
void BaseTest::onEnter()
TestBase::TestBase()
: _parentTest(nullptr)
, _isTestList(false)
{
Layer::onEnter();
AppDelegate* app = (AppDelegate *)Application::getInstance();
app->setCurrentTest(this);
// add title and subtitle
std::string str = title();
const char * pTitle = str.c_str();
TTFConfig ttfConfig("fonts/arial.ttf", 32);
auto label = Label::createWithTTF(ttfConfig,pTitle);
addChild(label, 9999);
label->setPosition(VisibleRect::center().x, VisibleRect::top().y - 30);
std::string strSubtitle = subtitle();
if( ! strSubtitle.empty() )
}
TestBase::~TestBase()
{
}
void TestBase::backsUpOneLevel()
{
if (_parentTest)
{
ttfConfig.fontFilePath = "fonts/Thonburi.ttf";
ttfConfig.fontSize = 16;
auto l = Label::createWithTTF(ttfConfig,strSubtitle.c_str());
addChild(l, 9999);
l->setPosition(VisibleRect::center().x, VisibleRect::top().y - 60);
_parentTest->runThisTest();
this->release();
}
}
//TestList
TestList::TestList()
{
_isTestList = true;
}
void TestList::addTest(const std::string& testName, std::function<TestBase*()> callback)
{
if (!testName.empty())
{
_childTestNames.push_back(testName);
_testCallbacks.push_back(callback);
}
}
void TestList::runThisTest()
{
_cellTouchEnabled = true;
auto director = Director::getInstance();
auto scene = Scene::create();
auto visibleSize = director->getVisibleSize();
auto origin = director->getVisibleOrigin();
TableView* tableView = TableView::create(this, Size(400,visibleSize.height));
tableView->setPosition(origin.x + (visibleSize.width - 400) / 2, origin.y);
tableView->setDirection(ScrollView::Direction::VERTICAL);
tableView->setVerticalFillOrder(TableView::VerticalFillOrder::TOP_DOWN);
tableView->setDelegate(this);
scene->addChild(tableView);
tableView->reloadData();
if (_tableOffset != Vec2::ZERO)
{
tableView->setContentOffset(_tableOffset);
}
// add menu
// CC_CALLBACK_1 == std::bind( function_ptr, instance, std::placeholders::_1, ...)
auto item1 = MenuItemImage::create(s_pathB1, s_pathB2, CC_CALLBACK_1(BaseTest::backCallback, this) );
auto item2 = MenuItemImage::create(s_pathR1, s_pathR2, CC_CALLBACK_1(BaseTest::restartCallback, this) );
auto item3 = MenuItemImage::create(s_pathF1, s_pathF2, CC_CALLBACK_1(BaseTest::nextCallback, this) );
if (_parentTest)
{
//Add back button.
TTFConfig ttfConfig("fonts/arial.ttf", 20);
auto label = Label::createWithTTF(ttfConfig, "Back");
auto menu = Menu::create(item1, item2, item3, nullptr);
auto menuItem = MenuItemLabel::create(label, std::bind(&TestBase::backsUpOneLevel, this));
auto menu = Menu::create(menuItem, nullptr);
menu->setPosition(Vec2::ZERO);
item1->setPosition(VisibleRect::center().x - item2->getContentSize().width*2, VisibleRect::bottom().y+item2->getContentSize().height/2);
item2->setPosition(VisibleRect::center().x, VisibleRect::bottom().y+item2->getContentSize().height/2);
item3->setPosition(VisibleRect::center().x + item2->getContentSize().width*2, VisibleRect::bottom().y+item2->getContentSize().height/2);
menu->setPosition(Vec2::ZERO);
menuItem->setPosition(Vec2(VisibleRect::right().x - 50, VisibleRect::bottom().y + 25));
addChild(menu, 9999);
scene->addChild(menu, 1);
}
else
{
//Add close and "Start AutoTest" button.
auto closeItem = MenuItemImage::create(s_pathClose, s_pathClose, [](Ref* sender){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.", "Alert");
return;
#endif
TestController::getInstance()->stopAutoTest();
TestController::destroyInstance();
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
});
closeItem->setPosition(VisibleRect::right().x - 30, VisibleRect::top().y - 30);
auto autoTestLabel = Label::createWithTTF("Start AutoTest","fonts/arial.ttf",16);
auto autoTestItem = MenuItemLabel::create(autoTestLabel, [&](Ref* sender){
TestController::getInstance()->startAutoTest();
});
autoTestItem->setPosition(Vec2(VisibleRect::right().x - 70, VisibleRect::bottom().y + 25));
auto menu = Menu::create(closeItem, autoTestItem, nullptr);
menu->setPosition(Vec2::ZERO);
scene->addChild(menu, 1);
}
director->replaceScene(scene);
}
void BaseTest::onExit()
void TestList::tableCellTouched(TableView* table, TableViewCell* cell)
{
AppDelegate* app = (AppDelegate *)Application::getInstance();
app->setCurrentTest(nullptr);
Layer::onExit();
if (_cellTouchEnabled)
{
auto index = cell->getIdx();
if (_testCallbacks[index])
{
auto test = _testCallbacks[index]();
if (test->getChildTestCount() > 0)
{
_tableOffset = table->getContentOffset();
_cellTouchEnabled = false;
test->setTestParent(this);
test->runThisTest();
}
else
{
delete test;
}
}
}
}
std::string BaseTest::title() const
TableViewCell* TestList::tableCellAtIndex(TableView *table, ssize_t idx)
{
return "";
auto cell = table->dequeueCell();
if (!cell)
{
cell = TableViewCell::create();
auto label = Label::createWithTTF(_childTestNames[idx], "fonts/arial.ttf", 20.0f);
label->setTag(1024);
label->setPosition(200, 25);
cell->addChild(label);
}
else
{
auto label = (Label*)cell->getChildByTag(1024);
label->setString(_childTestNames[idx]);
}
return cell;
}
std::string BaseTest::subtitle() const
Size TestList::tableCellSizeForIndex(TableView *table, ssize_t idx)
{
return "";
return Size(400, 50);
}
void BaseTest::restartCallback(Ref* sender)
ssize_t TestList::numberOfCellsInTableView(TableView *table)
{
log("override restart!");
return _childTestNames.size();
}
void BaseTest::nextCallback(Ref* sender)
//TestSuite
void TestSuite::addTestCase(const std::string& testName, std::function<Scene*()> callback)
{
log("override next!");
if (!testName.empty() && callback)
{
_childTestNames.push_back(testName);
_testCallbacks.push_back(callback);
}
}
void BaseTest::backCallback(Ref* sender)
static TestCase* getTestCase(Scene* scene)
{
log("override back!");
auto transitionScene = dynamic_cast<TransitionScene*>(scene);
TestCase* testCase = nullptr;
if (transitionScene)
{
testCase = dynamic_cast<TestCase*>(transitionScene->getInScene());
}
else
{
testCase = dynamic_cast<TestCase*>(scene);
}
return testCase;
}
void TestSuite::runThisTest()
{
if (!_childTestNames.empty())
{
_currTestIndex = 0;
auto scene = _testCallbacks[0]();
auto testCase = getTestCase(scene);
testCase->setTestSuite(this);
testCase->setTestCaseName(_childTestNames[_currTestIndex]);
Director::getInstance()->replaceScene(scene);
}
}
void TestSuite::restartCurrTest()
{
auto scene = _testCallbacks[_currTestIndex]();
auto testCase = getTestCase(scene);
testCase->setTestSuite(this);
testCase->setTestCaseName(_childTestNames[_currTestIndex]);
Director::getInstance()->replaceScene(testCase);
}
void TestSuite::enterNextTest()
{
_currTestIndex = (_currTestIndex + 1) % _childTestNames.size();
auto scene = _testCallbacks[_currTestIndex]();
auto testCase = getTestCase(scene);
testCase->setTestSuite(this);
testCase->setTestCaseName(_childTestNames[_currTestIndex]);
Director::getInstance()->replaceScene(testCase);
}
void TestSuite::enterPreviousTest()
{
if (_currTestIndex > 0)
{
_currTestIndex -= 1;
}
else
{
_currTestIndex = (int)_childTestNames.size() - 1;
}
auto scene = _testCallbacks[_currTestIndex]();
auto testCase = getTestCase(scene);
testCase->setTestSuite(this);
testCase->setTestCaseName(_childTestNames[_currTestIndex]);
Director::getInstance()->replaceScene(testCase);
}
//TestCase
TestCase::TestCase()
: _priorTestItem(nullptr)
, _restartTestItem(nullptr)
, _nextTestItem(nullptr)
, _titleLabel(nullptr)
, _subtitleLabel(nullptr)
, _testSuite(nullptr)
, _runTime(0.0f)
{
Director::getInstance()->getTextureCache()->removeUnusedTextures();
this->schedule([&](float dt){
_runTime += dt;
}, "AccumulatedTimeUse");
}
TestCase::~TestCase()
{
if (_testSuite)
{
_testSuite->release();
_testSuite = nullptr;
}
}
void TestCase::setTestSuite(TestSuite* testSuite)
{
if (_testSuite != testSuite)
{
testSuite->retain();
if (_testSuite)
{
_testSuite->release();
}
_testSuite = testSuite;
}
}
TestCase::Type TestCase::getTestType() const
{
return Type::ROBUSTNESS;
}
float TestCase::getDuration() const
{
return 0.2f;
}
bool TestCase::init()
{
if (Scene::init())
{
// add title and subtitle
TTFConfig ttfConfig("fonts/arial.ttf", 26);
_titleLabel = Label::createWithTTF(ttfConfig, title());
addChild(_titleLabel, 9999);
_titleLabel->setPosition(VisibleRect::center().x, VisibleRect::top().y - 30);
ttfConfig.fontSize = 16;
_subtitleLabel = Label::createWithTTF(ttfConfig, subtitle());
addChild(_subtitleLabel, 9999);
_subtitleLabel->setPosition(VisibleRect::center().x, VisibleRect::top().y - 60);
_priorTestItem = MenuItemImage::create(s_pathB1, s_pathB2, CC_CALLBACK_1(TestCase::priorTestCallback, this));
_restartTestItem = MenuItemImage::create(s_pathR1, s_pathR2, CC_CALLBACK_1(TestCase::restartTestCallback, this));
_nextTestItem = MenuItemImage::create(s_pathF1, s_pathF2, CC_CALLBACK_1(TestCase::nextTestCallback, this));
ttfConfig.fontSize = 20;
auto backLabel = Label::createWithTTF(ttfConfig, "Back");
auto backItem = MenuItemLabel::create(backLabel, CC_CALLBACK_1(TestCase::onBackCallback, this));
auto menu = Menu::create(_priorTestItem, _restartTestItem, _nextTestItem, backItem, nullptr);
menu->setPosition(Vec2::ZERO);
_priorTestItem->setPosition(VisibleRect::center().x - _restartTestItem->getContentSize().width * 2, VisibleRect::bottom().y + _restartTestItem->getContentSize().height / 2);
_restartTestItem->setPosition(VisibleRect::center().x, VisibleRect::bottom().y + _restartTestItem->getContentSize().height / 2);
_nextTestItem->setPosition(VisibleRect::center().x + _restartTestItem->getContentSize().width * 2, VisibleRect::bottom().y + _restartTestItem->getContentSize().height / 2);
backItem->setPosition(Vec2(VisibleRect::right().x - 50, VisibleRect::bottom().y + 25));
addChild(menu, 9999);
return true;
}
return false;
}
void TestCase::onEnter()
{
Scene::onEnter();
_titleLabel->setString(title());
_subtitleLabel->setString(subtitle());
if (_testSuite && _testSuite->getChildTestCount() < 2)
{
_priorTestItem->setVisible(false);
_nextTestItem->setVisible(false);
_restartTestItem->setVisible(false);
}
}
void TestCase::restartTestCallback(Ref* sender)
{
if (_testSuite)
{
_testSuite->restartCurrTest();
}
}
void TestCase::nextTestCallback(Ref* sender)
{
if (_testSuite)
{
_testSuite->enterNextTest();
}
}
void TestCase::priorTestCallback(Ref* sender)
{
if (_testSuite)
{
_testSuite->enterPreviousTest();
}
}
void TestCase::onBackCallback(Ref* sender)
{
if (_testSuite)
{
_testSuite->backsUpOneLevel();
}
}

View File

@ -1,5 +1,5 @@
/****************************************************************************
Copyright (c) 2013-2014 Chukong Technologies Inc.
Copyright (c) 2013-2015 Chukong Technologies Inc.
http://www.cocos2d-x.org
@ -22,24 +22,212 @@
THE SOFTWARE.
****************************************************************************/
#ifndef __TestCpp__BaseTest__
#define __TestCpp__BaseTest__
#ifndef _CPPTESTS_BASETEST_H__
#define _CPPTESTS_BASETEST_H__
#include "cocos2d.h"
#include "extensions/cocos-ext.h"
#include "VisibleRect.h"
class BaseTest : public cocos2d::Layer
USING_NS_CC;
USING_NS_CC_EXT;
class TestSuite;
/**
* Each test case should inherit from TestCase, and add to a TestSuite object.
*/
class TestCase : public Scene
{
public:
virtual std::string title() const;
virtual std::string subtitle() const;
/** TestCase test type.*/
enum class Type
{
/** For testing whether test case not crash.*/
ROBUSTNESS,
/**
* For check the correctness of regular test cases.
* A test case passes only if the actual output equal to the expected output.
*/
UNIT,
/** @warning The test type is not achieved.*/
GRAPHICAL_STATIC,
/** @note It's mean the test case need test manually.*/
MANUAL
};
TestCase();
~TestCase();
virtual void restartCallback(Ref* sender);
virtual void nextCallback(Ref* sender);
virtual void backCallback(Ref* sender);
virtual std::string title() const { return ""; }
virtual std::string subtitle() const { return ""; }
/** Returns the test type, the default type is Type::ROBUSTNESS.*/
virtual Type getTestType() const;
/** Returns the time the test case needs.*/
virtual float getDuration() const;
/** Returns the expected output.*/
virtual std::string getExpectedOutput() const { return ""; }
/** Returns the actual output.*/
virtual std::string getActualOutput() const { return ""; }
/** Callback functions.*/
virtual void restartTestCallback(Ref* sender);
virtual void nextTestCallback(Ref* sender);
virtual void priorTestCallback(Ref* sender);
virtual void onBackCallback(Ref* sender);
/**
* You should NEVER call this method, unless you know what you are doing.
*/
void setTestSuite(TestSuite* testSuite);
TestSuite* getTestSuite() const { return _testSuite; }
/** Returns the run time of test case.*/
float getRunTime() const { return _runTime; }
/**
* You should NEVER call this method, unless you know what you are doing.
*/
void setTestCaseName(const std::string& name) { _testCaseName = name; }
std::string getTestCaseName() const { return _testCaseName; }
virtual void onEnter() override;
virtual void onExit() override;
CC_CONSTRUCTOR_ACCESS:
virtual bool init() override;
protected:
MenuItemImage* _priorTestItem;
MenuItemImage* _restartTestItem;
MenuItemImage* _nextTestItem;
Label* _titleLabel;
Label* _subtitleLabel;
private:
TestSuite* _testSuite;
float _runTime;
std::string _testCaseName;
};
/**
* A TestBase object stores the following information about a test:
* - A pointer to the parent test(TestList or TestSuite).
* - Array of children test names.
* - A flag to indicate whether the test is a TestList object.
*
* @note You should not inherit from TestBase directly.
*/
class TestBase : public Ref
{
public:
virtual ~TestBase();
/** Backs up one level. */
void backsUpOneLevel();
virtual void runThisTest() {}
bool isTestList() { return _isTestList; }
ssize_t getChildTestCount() { return _childTestNames.size(); }
/**
* You should NEVER call this method.
*/
void setTestParent(TestBase* parent) { _parentTest = parent; }
TestBase* getTestParent() { return _parentTest; }
void setTestName(const std::string& testName) { _testName = testName; }
std::string getTestName() const { return _testName; }
protected:
TestBase();
std::string _testName;
TestBase* _parentTest;
bool _isTestList;
std::vector<std::string> _childTestNames;
};
class TestController;
/**
* TestSuite correspond to a group of test cases.
* @note Each test case should add to a TestSuite object.
*/
class TestSuite : public TestBase
{
public:
void addTestCase(const std::string& testName, std::function<Scene*()> callback);
virtual void restartCurrTest();
virtual void enterNextTest();
virtual void enterPreviousTest();
virtual void runThisTest() override;
private:
std::vector<std::function<Scene*()>> _testCallbacks;
int _currTestIndex;
friend class TestController;
};
/**
* An instance of TestList is a means for displaying hierarchical lists of TestSuite.
*/
class TestList : public TestBase, public TableViewDataSource, public TableViewDelegate
{
public:
TestList();
void addTest(const std::string& testName, std::function<TestBase*()> callback);
virtual void runThisTest() override;
virtual void tableCellTouched(TableView* table, TableViewCell* cell) override;
virtual TableViewCell* tableCellAtIndex(TableView *table, ssize_t idx) override;
virtual Size tableCellSizeForIndex(TableView *table, ssize_t idx) override;
virtual ssize_t numberOfCellsInTableView(TableView *table) override;
virtual void scrollViewDidScroll(cocos2d::extension::ScrollView* view) override{}
virtual void scrollViewDidZoom(cocos2d::extension::ScrollView* view) override{}
private:
std::vector<std::function<TestBase*()>> _testCallbacks;
bool _cellTouchEnabled;
Vec2 _tableOffset;
friend class TestController;
};
#endif /* defined(__TestCpp__BaseTest__) */
#define ADD_TEST(__className__) addTest( #__className__, [](){ return new (std::nothrow) __className__;} );
#define ADD_TEST_CASE(__className__) addTestCase( #__className__, [](){ return __className__::create();} );
#define DEFINE_TEST_LIST(__className__) class __className__ : public TestList { public: __className__();}
#define DEFINE_TEST_SUITE(__className__) class __className__ : public TestSuite { public: __className__();}
/**
* BaseTest is retained for compatibility with older versions.
* @warning It should soon be removed.
*/
class BaseTest : public cocos2d::Layer
{
public:
virtual std::string title() const { return ""; }
virtual std::string subtitle() const{ return ""; }
virtual void restartCallback(Ref* sender) {}
virtual void nextCallback(Ref* sender){}
virtual void backCallback(Ref* sender){}
virtual void onEnter() override{}
virtual void onExit() override{}
};
#endif /* defined(_CPPTESTS_BASETEST_H__) */

View File

@ -1,591 +1,421 @@
// C++ includes
#include <map>
#include <functional>
#include <string>
#include <chrono>
#include <thread>
// test inclues
#include "AppDelegate.h"
#include "BaseTest.h"
#include "controller.h"
#include "testResource.h"
#include <functional>
#include <chrono>
#include "BaseTest.h"
#include "tests.h"
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#else
#include <io.h>
#include <WS2tcpip.h>
#endif
#include "cocostudio/CocoStudio.h"
#include "UITest/UITest.h"
USING_NS_CC;
typedef struct _Controller{
const char *test_name;
std::function<TestScene*()> callback;
} Controller;
Controller g_aTestNames[] = {
#define TEST_TIME_OUT 25
#define CREATE_TIME_OUT 25
#define LOG_INDENTATION " "
#define LOG_TAG "[TestController]"
//
// TESTS MUST BE ORDERED ALPHABETICALLY
// violators will be prosecuted
//
{ "ActionManager", [](){return new ActionManagerTestScene(); } },
{ "Actions - Basic", [](){ return new ActionsTestScene(); } },
{ "Actions - Ease", [](){return new ActionsEaseTestScene();} },
{ "Actions - Progress", [](){return new ProgressActionsTestScene(); } },
{ "Allocator - Basic", [](){return new AllocatorTestNS::AllocatorTestScene(); } },
{ "Audio - CocosDenshion", []() { return new CocosDenshionTestScene(); } },
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(); });
#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)
{ "Audio - NewAudioEngine", []() { return new AudioEngineTestScene(); } },
addTest("Audio - NewAudioEngine", []() { return new (std::nothrow) AudioEngineTests(); });
#endif
#if CC_ENABLE_BOX2D_INTEGRATION
{ "Box2d - Basic", []() { return new Box2DTestScene(); } },
{ "Box2d - TestBed", []() { return new Box2dTestBedScene(); } },
addTest("Box2d - Basic", []() { return new (std::nothrow) Box2DTests(); });
addTest("Box2d - TestBed", []() { return new (std::nothrow) Box2dTestBedSuite(); });
#endif
{ "Bugs", []() { return new BugsTestScene(); } },
{ "Chipmunk", []() { return new ChipmunkAccelTouchTestScene(); } },
{ "Click and Move", [](){return new ClickAndMoveTestScene(); } },
{ "Configuration", []() { return new ConfigurationTestScene(); } },
{ "Console", []() { return new ConsoleTestScene(); } },
{ "Curl", []() { return new CurlTestScene(); } },
{ "Current Language", []() { return new CurrentLanguageTestScene(); } },
{ "CocosStudio3D Test", []() { return new CS3DTestScene(); } },
{ "EventDispatcher", []() { return new EventDispatcherTestScene(); } },
{ "Effects - Advanced", []() { return new EffectAdvanceScene(); } },
{ "Effects - Basic", [](){return new EffectTestScene();} },
{ "Extensions", []() { return new ExtensionsTestScene(); } },
{ "FileUtils", []() { return new FileUtilsTestScene(); } },
{ "Fonts", []() { return new FontTestScene(); } },
{ "Interval", [](){return new IntervalTestScene(); } },
{ "Node: BillBoard Test", [](){ return new BillBoardTestScene(); }},
{ "Node: Camera 3D Test", [](){ return new Camera3DTestScene(); }},
{ "Node: Clipping", []() { return new ClippingNodeTestScene(); } },
{ "Node: Draw", [](){return new DrawPrimitivesTestScene();} },
{ "Node: Label - New API", [](){return new AtlasTestSceneNew(); } },
{ "Node: Label - Old API", [](){return new AtlasTestScene(); } },
{ "Node: Layer", [](){return new LayerTestScene();} },
{ "Node: Light", [](){return new LightTestScene();} },
{ "Node: Menu", [](){return new MenuTestScene();} },
{ "Node: MotionStreak", [](){return new MotionStreakTestScene();} },
{ "Node: Node", [](){return new CocosNodeTestScene();} },
{ "Node: Parallax", [](){return new ParallaxTestScene(); } },
{ "Node: Particles", [](){return new ParticleTestScene(); } },
{ "Node: Particle3D (PU)", [](){ return new Particle3DTestScene(); }},
{ "Node: Physics", []() { return new PhysicsTestScene(); } },
{ "Node: RenderTexture", [](){return new RenderTextureScene(); } },
{ "Node: Scene", [](){return new SceneTestScene();} },
{ "Node: Spine", []() { return new SpineTestScene(); } },
{ "Node: Sprite", [](){return new SpriteTestScene(); } },
{ "Node: Sprite3D", [](){ return new Sprite3DTestScene(); }},
{ "Node: TileMap", [](){return new TileMapTestScene(); } },
{ "Node: FastTileMap", [](){return new TileMapTestSceneNew(); } },
{ "Node: Text Input", [](){return new TextInputTestScene(); } },
{ "Node: UI", [](){ return new UITestScene(); }},
{ "Mouse", []() { return new MouseTestScene(); } },
{ "MultiTouch", []() { return new MutiTouchTestScene(); } },
{ "Performance tests", []() { return new PerformanceTestScene(); } },
{ "Renderer", []() { return new NewRendererTestScene(); } },
{ "ReleasePool", [](){ return new ReleasePoolTestScene(); } },
{ "Rotate World", [](){return new RotateWorldTestScene(); } },
{ "Scheduler", [](){return new SchedulerTestScene(); } },
#if CC_TARGET_PLATFORM != CC_PLATFORM_WP8
{ "Shader - Basic", []() { return new ShaderTestScene(); } },
{ "Shader - Sprite", []() { return new ShaderTestScene2(); } },
#endif
{ "Texture2D", [](){return new TextureTestScene(); } },
{ "TextureCache", []() { return new TextureCacheTestScene(); } },
{ "TexturePacker Encryption", []() { return new TextureAtlasEncryptionTestScene(); } },
{ "Touches", [](){return new PongScene();} },
{ "Transitions", [](){return new TransitionsTestScene();} },
{ "Unit Test", []() { return new UnitTestScene(); }},
{ "URL Open Test", []() { return new OpenURLTestScene(); } },
{ "UserDefault", []() { return new UserDefaultTestScene(); } },
{ "Zwoptex", []() { return new ZwoptexTestScene(); } }
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(); });
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(); });
addTest("Node: Physics", []() { return new PhysicsTests(); });
addTest("Node: RenderTexture", [](){return new RenderTextureTests(); });
addTest("Node: Scene", [](){return new SceneTests(); });
addTest("Node: Sprite", [](){return new SpriteTests(); });
addTest("Node: Sprite3D", [](){ return new Sprite3DTests(); });
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(); });
}
};
static int g_testCount = sizeof(g_aTestNames) / sizeof(g_aTestNames[0]);
static Controller *currentController = nullptr;
#define LINE_SPACE 40
static Vec2 s_tCurPos = Vec2::ZERO;
//sleep for t seconds
static void wait(int t)
{
std::chrono::milliseconds dura( t * 1000 );
std::this_thread::sleep_for( dura );
}
TestController::TestController()
: _beginPos(Vec2::ZERO)
,_exitThread(false)
: _stopAutoTest(true)
, _isRunInBackground(false)
{
// add close menu
auto closeItem = MenuItemImage::create(s_pathClose, s_pathClose, CC_CALLBACK_1(TestController::closeCallback, this) );
auto menu =Menu::create(closeItem, nullptr);
_rootTestList = new (std::nothrow) RootTests;
_rootTestList->runThisTest();
_director = Director::getInstance();
menu->setPosition( Vec2::ZERO );
closeItem->setPosition(VisibleRect::right().x - 30, VisibleRect::top().y - 30);
_touchListener = EventListenerTouchOneByOne::create();
_touchListener->onTouchBegan = CC_CALLBACK_2(TestController::blockTouchBegan, this);
_touchListener->setSwallowTouches(true);
// add menu items for tests
TTFConfig ttfConfig("fonts/arial.ttf", 24);
_itemMenu = Menu::create();
for (int i = 0; i < g_testCount; ++i)
{
auto label = Label::createWithTTF(ttfConfig, g_aTestNames[i].test_name);
auto menuItem = MenuItemLabel::create(label, CC_CALLBACK_1(TestController::menuCallback, this));
_itemMenu->addChild(menuItem, i + 10000);
menuItem->setPosition(VisibleRect::center().x, (VisibleRect::top().y - (i + 1) * LINE_SPACE));
}
_itemMenu->setContentSize(Size(VisibleRect::getVisibleRect().size.width, (g_testCount + 1) * (LINE_SPACE)));
_itemMenu->setPosition(s_tCurPos);
addChild(_itemMenu);
addChild(menu, 1);
// Register Touch Event
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(TestController::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(TestController::onTouchMoved, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
auto mouseListener = EventListenerMouse::create();
mouseListener->onMouseScroll = CC_CALLBACK_1(TestController::onMouseScroll, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this);
_director->getEventDispatcher()->addEventListenerWithFixedPriority(_touchListener, -200);
}
TestController::~TestController()
{
_director->getEventDispatcher()->removeEventListener(_touchListener);
_rootTestList->release();
_rootTestList = nullptr;
}
void TestController::menuCallback(Ref * sender)
void TestController::startAutoTest()
{
Director::getInstance()->purgeCachedData();
// get the userdata, it's the index of the menu item clicked
auto menuItem = static_cast<MenuItem *>(sender);
int idx = menuItem->getLocalZOrder() - 10000;
// create the test scene and run it
auto scene = g_aTestNames[idx].callback();
if (scene)
if (!_autoTestThread.joinable())
{
scene->runThisTest();
scene->release();
_stopAutoTest = false;
_logIndentation = "";
_autoTestThread = std::thread(&TestController::traverseTestList, this, _rootTestList);
_autoTestThread.detach();
}
}
void TestController::closeCallback(Ref * sender)
void TestController::stopAutoTest()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
bool TestController::onTouchBegan(Touch* touch, Event *event)
{
_beginPos = touch->getLocation();
return true;
}
void TestController::onTouchMoved(Touch* touch, Event *event)
{
auto touchLocation = touch->getLocation();
float nMoveY = touchLocation.y - _beginPos.y;
auto curPos = _itemMenu->getPosition();
auto nextPos = Vec2(curPos.x, curPos.y + nMoveY);
if (nextPos.y < 0.0f)
{
_itemMenu->setPosition(Vec2::ZERO);
return;
}
if (nextPos.y > ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height))
{
_itemMenu->setPosition(0, ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height));
return;
}
_itemMenu->setPosition(nextPos);
_beginPos = touchLocation;
s_tCurPos = nextPos;
}
void TestController::onMouseScroll(Event *event)
{
auto mouseEvent = static_cast<EventMouse*>(event);
float nMoveY = mouseEvent->getScrollY() * 6;
auto curPos = _itemMenu->getPosition();
auto nextPos = Vec2(curPos.x, curPos.y + nMoveY);
if (nextPos.y < 0.0f)
{
_itemMenu->setPosition(Vec2::ZERO);
return;
}
if (nextPos.y > ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height))
{
_itemMenu->setPosition(0, ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height));
return;
}
_itemMenu->setPosition(nextPos);
s_tCurPos = nextPos;
}
void TestController::runAllTests(int fd)
{
AppDelegate* app = (AppDelegate *)Application::getInstance();
Scheduler *sched = Director::getInstance()->getScheduler();
for (int i = 0; i < g_testCount; i++)
{
// create the test scene and run it
std::string msg("autotest: running test:");
msg += g_aTestNames[i].test_name;
send(fd, msg.c_str(), strlen(msg.c_str()),0);
send(fd, "\n",1,0);
currentController = &g_aTestNames[i];
sched->performFunctionInCocosThread( [&](){
auto scene = currentController->callback();
if(scene)
{
scene->runThisTest();
scene->release();
}
} );
wait(1);
BaseTest* firstTest = app->getCurrentTest();
if(firstTest == nullptr)
{
continue;
}
std::string t1("");
t1 += firstTest->subtitle();
send(fd, t1.c_str(), strlen(t1.c_str()),0);
send(fd, "\n",1,0);
wait(2);
while(1)
{
if(_exitThread)
{
return;
}
//currentTest->nextCallback(nullptr);
sched->performFunctionInCocosThread( [&](){
BaseTest *t = app->getCurrentTest();
if(t != nullptr)
{
t->nextCallback(nullptr);
}
} );
wait(1);
BaseTest * curTest = app->getCurrentTest();
if(curTest == nullptr)
{
break;
}
std::string title("");
title += curTest->subtitle();
send(fd, title.c_str(), strlen(title.c_str()),0);
send(fd, "\n",1,0);
wait(2);
if(t1 == title)
{
break;
}
}
}
std::string msg("autotest run successfully!");
send(fd, msg.c_str(), strlen(msg.c_str()),0);
send(fd, "\n",1,0);
return;
}
void TestController::addConsoleAutoTest()
{
auto console = Director::getInstance()->getConsole();
_stopAutoTest = true;
static struct Console::Command autotest = {
"autotest",
"testcpp autotest command, use -h to list available tests",
[this](int fd, const std::string& args)
if (_autoTestThread.joinable()) {
_sleepCondition.notify_all();
_autoTestThread.join();
}
}
void TestController::traverseTestList(TestList* testList)
{
if (testList == _rootTestList)
{
_sleepUniqueLock = std::unique_lock<std::mutex>(_sleepMutex);
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(2500));
//disable touch
}
else
{
_logIndentation += LOG_INDENTATION;
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
}
logEx("%s%sBegin traverse TestList:%s", LOG_TAG, _logIndentation.c_str(), testList->getTestName().c_str());
auto scheduler = _director->getScheduler();
int testIndex = 0;
for (auto& callback : testList->_testCallbacks)
{
if (_stopAutoTest) break;
while (_isRunInBackground)
{
Scheduler *sched = Director::getInstance()->getScheduler();
if(args == "help" || args == "-h")
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())
{
const char msg[] = "usage: autotest ActionsTest\n\tavailable tests: ";
send(fd, msg, sizeof(msg),0);
send(fd, "\n",1,0);
for(int i = 0; i < g_testCount; i++)
{
send(fd, "\t",1,0);
send(fd, g_aTestNames[i].test_name, strlen(g_aTestNames[i].test_name)+1,0);
send(fd, "\n",1,0);
}
const char help_main[] = "\tmain, return to main menu\n";
send(fd, help_main, sizeof(help_main),0);
scheduler->performFunctionInCocosThread([&](){
test->runThisTest();
});
const char help_next[] = "\tnext, run next test\n";
send(fd, help_next, sizeof(help_next),0);
const char help_back[] = "\tback, run prev test\n";
send(fd, help_back, sizeof(help_back),0);
const char help_restart[] = "\trestart, restart current test\n";
send(fd, help_restart, sizeof(help_restart),0);
return;
traverseTestList((TestList*)test);
}
if(args == "main")
else
{
sched->performFunctionInCocosThread( [&]()
{
auto scene = Scene::create();
auto layer = new (std::nothrow) TestController();
scene->addChild(layer);
layer->release();
Director::getInstance()->replaceScene(scene);
cocostudio::ArmatureDataManager::destroyInstance();
} );
return;
}
const char msg_notest[] = "autotest: can't detect running test.\n";
AppDelegate* app = (AppDelegate *)Application::getInstance();
BaseTest* currentTest = app->getCurrentTest();
if(args == "next")
{
if(currentTest != nullptr)
{
//currentTest->nextCallback(nullptr);
sched->performFunctionInCocosThread( [&](){
currentTest->nextCallback(nullptr);
} );
}
else
{
send(fd, msg_notest, sizeof(msg_notest),0);
}
return;
}
if(args == "back")
{
if(currentTest != nullptr)
{
sched->performFunctionInCocosThread( [&](){
currentTest->backCallback(nullptr);
} );
}
else
{
send(fd, msg_notest, sizeof(msg_notest),0);
}
return;
traverseTestSuite((TestSuite*)test);
}
}
}
if(args == "restart")
{
if(currentTest != nullptr)
{
sched->performFunctionInCocosThread( [&](){
currentTest->restartCallback(nullptr);
} );
}
else
{
send(fd, msg_notest, sizeof(msg_notest),0);
}
return;
}
if(args == "run")
{
_exitThread = false;
std::thread t = std::thread( &TestController::runAllTests, this, fd);
t.detach();
return;
}
if(args == "stop")
{
_exitThread = true;
std::string msg("autotest: autotest stopped!");
send(fd, msg.c_str(), strlen(msg.c_str()),0);
send(fd, "\n",1,0);
return;
}
for(int i = 0; i < g_testCount; i++)
{
if(args == g_aTestNames[i].test_name)
{
currentController = &g_aTestNames[i];
std::string msg("autotest: running test:");
msg += args;
send(fd, msg.c_str(), strlen(msg.c_str()),0);
send(fd, "\n",1,0);
sched->performFunctionInCocosThread( [&](){
auto scene = currentController->callback();
if(scene)
{
scene->runThisTest();
scene->release();
}
} );
return;
}
}
//no match found,print warning message
std::string msg("autotest: could not find test:");
msg += args;
send(fd, msg.c_str(), strlen(msg.c_str()),0);
send(fd, "\n",1,0);
if (testList == _rootTestList)
{
_sleepUniqueLock.release();
_stopAutoTest = true;
}
else
{
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();
}
};
console->addCommand(autotest);
_logIndentation.erase(_logIndentation.rfind(LOG_INDENTATION));
}
}
void TestController::startAutoRun()
void TestController::traverseTestSuite(TestSuite* testSuite)
{
std::thread t = std::thread( &TestController::autorun, this);
t.detach();
}
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());
ssize_t TestController::readline(int fd, char* ptr, size_t maxlen)
{
size_t n, rc;
char c;
_logIndentation += LOG_INDENTATION;
for( n = 0; n < maxlen - 1; n++ ) {
if( (rc = recv(fd, &c, 1, 0)) ==1 ) {
*ptr++ = c;
if(c == '\n') {
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)
{
logEx("_director is paused");
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
}
//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());
auto scene = callback();
if (_stopAutoTest) return;
if (scene)
{
transitionScene = dynamic_cast<TransitionScene*>(scene);
if (transitionScene)
{
testCase = (TestCase*)transitionScene->getInScene();
testCaseDuration = transitionScene->getDuration() + 0.5f;
}
else
{
testCase = (TestCase*)scene;
testCaseDuration = testCase->getDuration();
}
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)
{
waitTime += 0.05f;
}
if (waitTime > CREATE_TIME_OUT)
{
logEx("%sCreate test %s time out", LOG_TAG, testName.c_str());
_stopAutoTest = true;
break;
}
} else if( rc == 0 ) {
return 0;
} else if( errno == EINTR ) {
continue;
} else {
return -1;
}
if (_stopAutoTest) break;
//Wait for test completed.
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(int(1000 * testCaseDuration)));
if (transitionScene == nullptr)
{
waitTime = 0.0f;
while (!_stopAutoTest && testCase->getRunTime() < testCaseDuration)
{
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(50));
if (!_isRunInBackground)
{
waitTime += 0.05f;
}
if (waitTime > TEST_TIME_OUT)
{
logEx("%sRun test %s time out", LOG_TAG, testName.c_str());
_stopAutoTest = true;
break;
}
}
if (!_stopAutoTest)
{
//Check the result of test.
checkTest(testCase);
}
}
}
*ptr = 0;
return n;
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));
}
void TestController::autorun()
bool TestController::checkTest(TestCase* testCase)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* stream socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2),&wsaData);
#endif
s = getaddrinfo("localhost", "5678", &hints, &result);
if (s != 0)
if (testCase)
{
CCLOG("autotest: getaddrinfo error");
return;
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != nullptr; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
closesocket(sfd);
#else
close(sfd);
#endif
}
if (rp == nullptr) { /* No address succeeded */
CCLOG("autotest: could not connect!");
return;
}
freeaddrinfo(result); /* No longer needed */
std::string tmp = "autotest run\n";
char cmd[512];
strcpy(cmd, tmp.c_str());
wait(3);
send(sfd,cmd,strlen(cmd),0);
while(true)
{
char resp[512];
readline(sfd, resp, 512);
if(strcmp(resp, "autotest run successfully!\n") == 0)
switch (testCase->getTestType())
{
case TestCase::Type::UNIT:
{
if (testCase && testCase->getExpectedOutput() != testCase->getActualOutput())
{
logEx("%s %s test fail", LOG_TAG, testCase->getTestCaseName().c_str());
}
else
{
logEx("%s %s test pass", LOG_TAG, testCase->getTestCaseName().c_str());
}
break;
}
case TestCase::Type::ROBUSTNESS:
{
break;
}
wait(3);
case TestCase::Type::MANUAL:
{
break;
}
default:
break;
}
}
tmp = "director end\n";
strcpy(cmd, tmp.c_str());
send(sfd,cmd,strlen(cmd),0);
wait(1);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
closesocket(sfd);
WSACleanup();
#else
close(sfd);
#endif
return;
return true;
}
void TestController::handleCrash()
{
logEx("TestController::handleCrash");
stopAutoTest();
}
void TestController::onEnterBackground()
{
_isRunInBackground = true;
}
void TestController::onEnterForeground()
{
_isRunInBackground = false;
}
void TestController::logEx(const char * format, ...)
{
char buff[1024];
va_list args;
va_start(args, format);
vsnprintf(buff, 1020, format, args);
strcat(buff, "\n");
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
__android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", "%s", buff);
#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);
#else
// Linux, Mac, iOS, etc
fprintf(stdout, "%s", buff);
fflush(stdout);
#endif
va_end(args);
}
static TestController* s_testController = nullptr;
TestController* TestController::getInstance()
{
if (s_testController == nullptr)
{
s_testController = new (std::nothrow) TestController;
}
return s_testController;
}
void TestController::destroyInstance()
{
if (s_testController)
{
s_testController->stopAutoTest();
delete s_testController;
s_testController = nullptr;
}
}
bool TestController::blockTouchBegan(Touch* touch, Event* event)
{
return !_stopAutoTest;
}

View File

@ -1,32 +1,88 @@
#ifndef _CONTROLLER_H_
#define _CONTROLLER_H_
/****************************************************************************
Copyright (c) 2013-2015 Chukong Technologies Inc.
#include "cocos2d.h"
http://www.cocos2d-x.org
USING_NS_CC;
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
class TestController : public Layer
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef _CPPTESTS_CONTROLLER_H__
#define _CPPTESTS_CONTROLLER_H__
#include <condition_variable>
#include <string>
#include <thread>
class TestList;
class TestSuite;
class TestCase;
namespace cocos2d
{
class Director;
class Touch;
class Event;
class EventListenerTouchOneByOne;
}
class TestController
{
public:
static TestController* getInstance();
static void destroyInstance();
TestController();
~TestController();
void menuCallback(Ref * sender);
void closeCallback(Ref * sender);
void startAutoTest();
void stopAutoTest();
bool onTouchBegan(Touch* touches, Event *event);
void onTouchMoved(Touch* touches, Event *event);
void handleCrash();
void onMouseScroll(Event *event);
void addConsoleAutoTest();
void autorun();
void startAutoRun();
void runAllTests(int fd);
ssize_t readline(int fd, char* ptr, size_t maxlen);
void onEnterBackground();
void onEnterForeground();
bool blockTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
private:
Vec2 _beginPos;
Menu* _itemMenu;
bool _exitThread;
static void logEx(const char * format, ...);
bool _stopAutoTest;
TestList* _rootTestList;
std::thread _autoTestThread;
std::mutex _sleepMutex;
std::condition_variable _sleepCondition;
std::unique_lock<std::mutex> _sleepUniqueLock;
cocos2d::Director* _director;
cocos2d::EventListenerTouchOneByOne* _touchListener;
std::string _logIndentation;
bool _isRunInBackground;
void traverseTestList(TestList* testList);
void traverseTestSuite(TestSuite* testSuite);
bool checkTest(TestCase* testCase);
};
#endif

View File

@ -1,50 +0,0 @@
#include "testBasic.h"
#include "controller.h"
#include "extensions/cocos-ext.h"
#include "cocostudio/CocoStudio.h"
TestScene::TestScene(bool bPortrait, bool physics/* = false*/)
{
if (physics)
{
#if CC_USE_PHYSICS
TestScene::initWithPhysics();
#else
Scene::init();
#endif
}
else
{
Scene::init();
}
}
void testScene_callback(Ref *sender )
{
auto scene = Scene::create();
auto layer = new (std::nothrow) TestController();
scene->addChild(layer);
layer->release();
Director::getInstance()->replaceScene(scene);
cocostudio::ArmatureDataManager::destroyInstance();
}
void TestScene::onEnter()
{
Scene::onEnter();
//add the menu item for back to main menu
TTFConfig ttfConfig("fonts/arial.ttf", 20);
auto label = Label::createWithTTF(ttfConfig,"MainMenu");
auto menuItem = MenuItemLabel::create(label, testScene_callback );
auto menu = Menu::create(menuItem, nullptr);
menu->setPosition( Vec2::ZERO );
menuItem->setPosition( Vec2( VisibleRect::right().x - 50, VisibleRect::bottom().y + 25) );
addChild(menu, 1);
}

View File

@ -7,11 +7,15 @@
USING_NS_CC;
/**
* TestScene is retained for compatibility with older versions.
* @warning It should soon be removed.
*/
class TestScene : public Scene
{
public:
TestScene(bool bPortrait = false, bool physics = false);
virtual void onEnter() override;
TestScene(bool bPortrait = false, bool physics = false){}
virtual void onEnter() override {}
virtual void runThisTest() = 0;
};

View File

@ -82,5 +82,6 @@
#include "OpenURLTest/OpenURLTest.h"
#include "AllocatorTest/AllocatorTest.h"
#include "CocosStudio3DTest/CocosStudio3DTest.h"
#include "UITest/UITest.h"
#endif