2
0

unitTesting.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2014 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "unitTesting.h"
  23. #include "app/mainLoop.h"
  24. #include "console/console.h"
  25. #include "console/script.h"
  26. #include "console/engineAPI.h"
  27. #include "console/consoleInternal.h"
  28. #include "gfx/gfxInit.h"
  29. #if defined(TORQUE_OS_WIN)
  30. #define _CRTDBG_MAP_ALLOC
  31. #include <crtdbg.h>
  32. #endif
  33. //-----------------------------------------------------------------------------
  34. class TorqueUnitTestListener : public ::testing::EmptyTestEventListener
  35. {
  36. // Called before a test starts.
  37. virtual void OnTestStart(const ::testing::TestInfo& testInfo)
  38. {
  39. if (mVerbose)
  40. Con::printf("> Starting Test '%s.%s'",
  41. testInfo.test_case_name(), testInfo.name());
  42. }
  43. // Called after a failed assertion or a SUCCEED() invocation.
  44. virtual void OnTestPartResult(const ::testing::TestPartResult& testPartResult)
  45. {
  46. if (testPartResult.failed())
  47. {
  48. Con::warnf(">> Failed with '%s' in '%s' at (line:%d)\n",
  49. testPartResult.summary(),
  50. testPartResult.file_name(),
  51. testPartResult.line_number()
  52. );
  53. }
  54. else if (mVerbose)
  55. {
  56. Con::printf(">> Passed with '%s' in '%s' at (line:%d)",
  57. testPartResult.summary(),
  58. testPartResult.file_name(),
  59. testPartResult.line_number()
  60. );
  61. }
  62. }
  63. // Called after a test ends.
  64. virtual void OnTestEnd(const ::testing::TestInfo& testInfo)
  65. {
  66. if (testInfo.result()->Failed())
  67. {
  68. Con::printf("TestClass:%s Test:%s Failed!",
  69. testInfo.test_case_name(), testInfo.name());
  70. }
  71. if (!mVerbose)
  72. return;
  73. else if(testInfo.result()->Passed())
  74. {
  75. Con::printf("TestClass:%s Test:%s Succeeded!",
  76. testInfo.test_case_name(), testInfo.name());
  77. }
  78. else
  79. {
  80. Con::printf("TestClass:%s Test:%s Skipped!",
  81. testInfo.test_case_name(), testInfo.name());
  82. }
  83. Con::printf("> Ending Test\n");
  84. }
  85. bool mVerbose;
  86. public:
  87. TorqueUnitTestListener(bool verbose) : mVerbose(verbose) {}
  88. };
  89. class MemoryLeakDetector : public ::testing::EmptyTestEventListener
  90. {
  91. public:
  92. virtual void OnTestStart(const ::testing::TestInfo& testInfo)
  93. {
  94. #if defined(TORQUE_OS_WIN)
  95. _CrtMemCheckpoint(&memState_);
  96. #endif
  97. }
  98. virtual void OnTestEnd(const ::testing::TestInfo& testInfo)
  99. {
  100. if (testInfo.result()->Passed())
  101. {
  102. #if defined(TORQUE_OS_WIN)
  103. _CrtMemState stateNow, stateDiff;
  104. _CrtMemCheckpoint(&stateNow);
  105. int diffResult = _CrtMemDifference(&stateDiff, &memState_, &stateNow);
  106. if (diffResult)
  107. {
  108. FAIL() << "Memory leak of " << stateDiff.lSizes[1] << " byte(s) detected.";
  109. }
  110. #endif
  111. }
  112. }
  113. private:
  114. #if defined(TORQUE_OS_WIN)
  115. _CrtMemState memState_;
  116. #endif
  117. public:
  118. MemoryLeakDetector() {}
  119. };
  120. class TorqueScriptFixture : public testing::Test {};
  121. class TorqueScriptTest : public TorqueScriptFixture {
  122. public:
  123. explicit TorqueScriptTest(const char* pFunctionName) : mFunctionName(pFunctionName) {}
  124. void TestBody() override
  125. {
  126. Con::executef(mFunctionName);
  127. }
  128. private:
  129. const char* mFunctionName;
  130. };
  131. int main(int argc, char** argv)
  132. {
  133. testing::GTEST_FLAG(output) = "xml:test_detail.xml";
  134. testing::GTEST_FLAG(stack_trace_depth) = 10;
  135. printf("Running main() from %s\n", __FILE__);
  136. // Initialize Google Test.
  137. testing::InitGoogleTest(&argc, argv);
  138. // torques handle command.
  139. StandardMainLoop::init();
  140. // setup torque for testing.
  141. GFXInit::enumerateAdapters();
  142. GFXAdapter* a = GFXInit::chooseAdapter(NullDevice, "");
  143. GFXDevice* newDevice = GFX;
  144. if (newDevice == NULL)
  145. newDevice = GFXInit::createDevice(a);
  146. newDevice->setAllowRender(false);
  147. // required for tests that add gui elements.
  148. Con::evaluate("if (!isObject(GuiDefaultProfile)) new GuiControlProfile(GuiDefaultProfile){}; if (!isObject(GuiTooltipProfile)) new GuiControlProfile(GuiTooltipProfile){};");
  149. // this call is to add the tests that exist in runTests.tscript
  150. // note these tests will not appear in the test explorer.
  151. if(argc > 1)
  152. StandardMainLoop::handleCommandLine(argc, (const char**)argv);
  153. // run tests.
  154. int res = RUN_ALL_TESTS();
  155. StandardMainLoop::shutdown();
  156. return 0;
  157. }
  158. DefineEngineFunction(addUnitTest, void, (const char* function), ,
  159. "Add a TorqueScript function as a GTest unit test.\n"
  160. "@note This is only implemented rudimentarily to open the door for future development in unit-testing the engine.\n"
  161. "@tsexample\n"
  162. "function MyTest() {\n"
  163. " expectTrue(2+2 == 4, \"basic math should work\");\n"
  164. "}\n"
  165. "addUnitTest(MyTest);\n"
  166. "@endtsexample\n"
  167. "@see expectTrue")
  168. {
  169. Namespace::Entry* entry = Namespace::global()->lookup(StringTable->insert(function));
  170. const char* file = __FILE__;
  171. U32 ln = __LINE__;
  172. if (entry != NULL)
  173. {
  174. file = entry->mModule->getName();
  175. U32 inst;
  176. entry->mModule->findBreakLine(entry->mFunctionOffset, ln, inst);
  177. }
  178. else
  179. {
  180. Con::warnf("failed to register unit test %s, could not find the function", function);
  181. }
  182. testing::RegisterTest("TorqueScriptFixture", function, NULL, NULL, file, ln,
  183. [=]() -> TorqueScriptFixture* { return new TorqueScriptTest(function); });
  184. }
  185. String scriptFileMessage(const char* message)
  186. {
  187. Dictionary* frame = Con::getCurrentStackFrame();
  188. Con::Module* module = frame->module;
  189. const char* scriptLine = module->getFileLine(frame->ip);
  190. return String::ToString("at %s: %s", scriptLine, message);
  191. }
  192. DefineEngineFunction(expectTrue, void, (bool test, const char* message), (""),
  193. "TorqueScript wrapper around the EXPECT_TRUE assertion in GTest.\n"
  194. "@tsexample\n"
  195. "expectTrue(2+2 == 4, \"basic math should work\");\n"
  196. "@endtsexample")
  197. {
  198. EXPECT_TRUE(test) << scriptFileMessage(message).c_str();
  199. }