llimageworker_test.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:11k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llimageworker_test.cpp
  3.  * @author Merov Linden
  4.  * @date 2009-04-28
  5.  *
  6.  * $LicenseInfo:firstyear=2006&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2006-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  */
  33. // Precompiled header: almost always required for newview cpp files
  34. #include <list>
  35. #include <map>
  36. #include <algorithm>
  37. // Class to test
  38. #include "../llimageworker.h"
  39. // For timer class
  40. #include "../llcommon/lltimer.h"
  41. // Tut header
  42. #include "../test/lltut.h"
  43. // -------------------------------------------------------------------------------------------
  44. // Stubbing: Declarations required to link and run the class being tested
  45. // Notes: 
  46. // * Add here stubbed implementation of the few classes and methods used in the class to be tested
  47. // * Add as little as possible (let the link errors guide you)
  48. // * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
  49. // * A simulator for a class can be implemented here. Please comment and document thoroughly.
  50. LLImageBase::LLImageBase() {}
  51. LLImageBase::~LLImageBase() {}
  52. void LLImageBase::dump() { }
  53. void LLImageBase::sanityCheck() { }
  54. void LLImageBase::deleteData() { }
  55. U8* LLImageBase::allocateData(S32 size) { return NULL; }
  56. U8* LLImageBase::reallocateData(S32 size) { return NULL; }
  57. LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) { }
  58. LLImageRaw::~LLImageRaw() { }
  59. void LLImageRaw::deleteData() { }
  60. U8* LLImageRaw::allocateData(S32 size) { return NULL; }
  61. U8* LLImageRaw::reallocateData(S32 size) { return NULL; }
  62. // End Stubbing
  63. // -------------------------------------------------------------------------------------------
  64. // -------------------------------------------------------------------------------------------
  65. // TUT
  66. // -------------------------------------------------------------------------------------------
  67. namespace tut
  68. {
  69. // Test wrapper declarations
  70. // Note: We derive the responder class for 2 reasons:
  71. // 1. It's a pure virtual class and we can't compile without completed() being implemented
  72. // 2. We actually need a responder to test that the thread work test completed
  73. // We implement this making no assumption on what's done in the thread or worker
  74. // though, just that the responder's completed() method is called in the end.
  75. // Note on responders: responders are ref counted and *will* be deleted by the request they are 
  76. // attached to when the queued request is deleted. The recommended way of using them is to 
  77. // create them when creating a request, put a callback method in completed() and not rely on 
  78. // anything to survive in the responder object once completed() has been called. Let the request
  79. // do the deletion and clean up itself.
  80. class responder_test : public LLImageDecodeThread::Responder
  81. {
  82. public:
  83. responder_test(bool* res)
  84. done = res;
  85. *done = false;
  86. }
  87. virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
  88. {
  89. *done = true;
  90. }
  91. private:
  92. // This is what can be thought of as the minimal implementation of a responder
  93. // Done will be switched to true when completed() is called and can be tested
  94. // outside the responder. A better way of doing this is to store a callback here.
  95. bool* done;
  96. };
  97. // Test wrapper declaration : decode thread
  98. struct imagedecodethread_test
  99. {
  100. // Instance to be tested
  101. LLImageDecodeThread* mThread;
  102. // Constructor and destructor of the test wrapper
  103. imagedecodethread_test()
  104. {
  105. mThread = NULL;
  106. }
  107. ~imagedecodethread_test()
  108. {
  109. delete mThread;
  110. }
  111. };
  112. // Test wrapper declaration : image worker
  113. // Note: this class is not meant to be instantiated outside an LLImageDecodeThread instance
  114. // but it's not a bad idea to get its public API a good shake as part of a thorough unit test set.
  115. // Some gotcha with the destructor though (see below).
  116. struct imagerequest_test
  117. {
  118. // Instance to be tested
  119. LLImageDecodeThread::ImageRequest* mRequest;
  120. bool done;
  121. // Constructor and destructor of the test wrapper
  122. imagerequest_test()
  123. {
  124. done = false;
  125. mRequest = new LLImageDecodeThread::ImageRequest(0, 0,
  126.  LLQueuedThread::PRIORITY_NORMAL, 0, FALSE,
  127.  new responder_test(&done));
  128. }
  129. ~imagerequest_test()
  130. {
  131. // We should delete the object *but*, because its destructor is protected, that cannot be
  132. // done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...
  133. //delete mRequest;
  134. }
  135. };
  136. // Tut templating thingamagic: test group, object and test instance
  137. typedef test_group<imagedecodethread_test> imagedecodethread_t;
  138. typedef imagedecodethread_t::object imagedecodethread_object_t;
  139. tut::imagedecodethread_t tut_imagedecodethread("imagedecodethread");
  140. typedef test_group<imagerequest_test> imagerequest_t;
  141. typedef imagerequest_t::object imagerequest_object_t;
  142. tut::imagerequest_t tut_imagerequest("imagerequest");
  143. // ---------------------------------------------------------------------------------------
  144. // Test functions
  145. // Notes:
  146. // * Test as many as you possibly can without requiring a full blown simulation of everything
  147. // * The tests are executed in sequence so the test instance state may change between calls
  148. // * Remember that you cannot test private methods with tut
  149. // ---------------------------------------------------------------------------------------
  150. // ---------------------------------------------------------------------------------------
  151. // Test the LLImageDecodeThread interface
  152. // ---------------------------------------------------------------------------------------
  153. //
  154. // Note on Unit Testing Queued Thread Classes
  155. //
  156. // Since methods on such a class are called on a separate loop and that we can't insert tut
  157. // ensure() calls in there, we exercise the class with 2 sets of tests:
  158. // - 1: Test as a single threaded instance: We declare the class but ask for no thread
  159. //   to be spawned (easy with LLThreads since there's a boolean argument on the constructor
  160. //   just for that). We can then unit test each public method like we do on a normal class.
  161. // - 2: Test as a threaded instance: We let the thread launch and check that its external 
  162. //   behavior is as expected (i.e. it runs, can accept a work order and processes
  163. //   it). Typically though there's no guarantee that this exercises all the methods of the
  164. //   class which is why we also need the previous "non threaded" set of unit tests for
  165. //   complete coverage.
  166. //
  167. // ---------------------------------------------------------------------------------------
  168. template<> template<>
  169. void imagedecodethread_object_t::test<1>()
  170. {
  171. // Test a *non threaded* instance of the class
  172. mThread = new LLImageDecodeThread(false);
  173. ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL);
  174. // Test that we start with an empty list right at creation
  175. ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0);
  176. // Insert something in the queue
  177. bool done = false;
  178. LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
  179. // Verifies we got a valid handle
  180. ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0);
  181. // Verifies that we do now have something in the queued list
  182. ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1);
  183. // Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop)
  184. S32 res = mThread->update(0);
  185. // Verifies that we successfully handled the list
  186. ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0);
  187. // Verifies that the list is now empty
  188. ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0);
  189. }
  190. template<> template<>
  191. void imagedecodethread_object_t::test<2>()
  192. {
  193. // Test a *threaded* instance of the class
  194. mThread = new LLImageDecodeThread(true);
  195. ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
  196. // Test that we start with an empty list right at creation
  197. ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0);
  198. // Insert something in the queue
  199. bool done = false;
  200. LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
  201. // Verifies we get back a valid handle
  202. ensure("LLImageDecodeThread:  threaded decodeImage(), returned handle is null", decodeHandle != 0);
  203. // Wait a little so to simulate the main thread doing something on its main loop...
  204. ms_sleep(500); // 500 milliseconds
  205. // Verifies that the responder has *not* been called yet in the meantime
  206. ensure("LLImageDecodeThread: responder creation failed", done == false);
  207. // Ask the thread to update: that means tells the queue to check itself and creates work requests
  208. mThread->update(1);
  209. // Wait till the thread has time to handle the work order (though it doesn't do much per work order...)
  210. const U32 INCREMENT_TIME = 500; // 500 milliseconds
  211. const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more
  212. U32 total_time = 0;
  213. while ((done == false) && (total_time < MAX_TIME))
  214. {
  215. ms_sleep(INCREMENT_TIME);
  216. total_time += INCREMENT_TIME;
  217. }
  218. // Verifies that the responder has now been called
  219. ensure("LLImageDecodeThread: threaded work unit not processed", done == true);
  220. }
  221. // ---------------------------------------------------------------------------------------
  222. // Test the LLImageDecodeThread::ImageRequest interface
  223. // ---------------------------------------------------------------------------------------
  224. template<> template<>
  225. void imagerequest_object_t::test<1>()
  226. {
  227. // Test that we start with a correct request at creation
  228. ensure("LLImageDecodeThread::ImageRequest::ImageRequest() constructor test failed", mRequest->tut_isOK());
  229. bool res = mRequest->processRequest();
  230. // Verifies that we processed the request successfully
  231. ensure("LLImageDecodeThread::ImageRequest::processRequest() processing request test failed", res == true);
  232. // Check that we can call the finishing call safely
  233. try {
  234. mRequest->finishRequest(false);
  235. } catch (...) {
  236. fail("LLImageDecodeThread::ImageRequest::finishRequest() test failed");
  237. }
  238. }
  239. }