Posted By

DrPepper on 10/05/11


Tagged


Versions (?)

[cisp430] pqexam1.cpp


 / Published in: C++
 

  1. // FILE: pqexam1.cxx
  2. // Non-interactive test program for the PriorityQueue class,
  3. // with improved test for heap leaks.
  4. //
  5. // DESCRIPTION:
  6. // Each function of this program tests part of the
  7. // PriorityQueue class, returning
  8. // some number of points to indicate how much of the test was passed.
  9. // A description and result of each test is printed to cout.
  10. // Maximum number of points awarded by this program is determined by the
  11. // constants POINTS[1], POINTS[2]...
  12. //
  13. // WHAT'S NEW:
  14. // This new version of the test program includes an improved test for heap
  15. // leaks by overriding the new and delete operators. Users should consider
  16. // placing these new and delete operators into a separate cxx file, but
  17. // I have included everything in one file for easier distribution.
  18.  
  19. //#include <iostream.h> // Provides cout.
  20. #include <string.h> // Provides memcpy.
  21. #include <stdlib.h> // Provides size_t.
  22. #include "pqueue1.h" // Provides the PriorityQueue class.
  23.  
  24. #include <iostream>
  25.  
  26. using std::cout;
  27. using std::cin;
  28. using std::endl;
  29. using std::flush;
  30.  
  31.  
  32. // Descriptions and points for each of the tests:
  33. const size_t MANY_TESTS = 4;
  34. const int POINTS[MANY_TESTS+1] = {
  35. 200, // Total points for all tests.
  36. 100, // Test 1 points
  37. 50, // Test 2 points
  38. 25, // Test 3 points
  39. 25 // Test 4 points
  40. };
  41. const char DESCRIPTION[MANY_TESTS+1][256] = {
  42. "tests for the PriorityQueue class",
  43. "simple tests of insert and get_front",
  44. "Testing for possible heap leaks",
  45. "Testing the copy constructor",
  46. "Testing the assignment operator"
  47. };
  48.  
  49. // **************************************************************************
  50. // Replacements for new and delete:
  51. // The next two functions replace the new and delete operators. Any code
  52. // that is linked with this .cxx file will use these replacements instead
  53. // of the standard new and delete. The replacements provide three features:
  54. // 1. The global variable memory_used_now keeps track of how much memory has
  55. // been allocated by calls to new. (The global variable is static so that
  56. // it cannot be accessed outside of this .cxx file.)
  57. // 2. The new operator fills all newly allocated memory with a GARBAGE char.
  58. // 3. Each block of newly allocated memory is preceeded and followed by a
  59. // border of BORDER_SIZE characters. The first part of the front border
  60. // contains a copy of the size of the allocated memory. The rest of the
  61. // border contains a BORDER char.
  62. // During any delete operation, the border characters are checked. If any
  63. // border character has been changed from BORDER to something else, then an
  64. // error message is printed and the program is halted. This stops most
  65. // cases of writing beyond the ends of the allocated memory.
  66. // **************************************************************************
  67.  
  68. const size_t BORDER_SIZE = 2*sizeof(double);
  69. const char GARBAGE = 'g';
  70. const char BORDER = 'b';
  71. static size_t memory_used_now = 0;
  72.  
  73. void* operator new(size_t size)
  74. {
  75. char *whole_block; // Pointer to the entire block that we get from heap
  76. size_t *size_spot; // Spot in the block where to store a copy of size
  77. char *front_border; // The border bytes in front of the user's memory
  78. char *middle; // The memory to be given to the calling program
  79. char *back_border; // The border bytes at the back of the user's memory
  80. size_t i; // Loop control variable
  81.  
  82. // Allocate the block of memory for the user and for the two borders.
  83. whole_block = (char *) malloc(2*BORDER_SIZE + size);
  84. if (whole_block == NULL)
  85. {
  86. cout << "Insufficient memory for a call to the new operator." << endl;
  87. exit(0);
  88. }
  89.  
  90. // Figure out the start points of the various pieces of the block.
  91. size_spot = (size_t *) whole_block;
  92. front_border = (char *) (whole_block + sizeof(size_t));
  93. middle = (char *) (whole_block + BORDER_SIZE);
  94. back_border = middle + size;
  95.  
  96. // Put a copy of the size at the start of the block.
  97. *size_spot = size;
  98.  
  99. // Fill the borders and the middle section.
  100. for (i = 0; i < BORDER_SIZE - sizeof(size_t); i++)
  101. front_border[i] = BORDER;
  102. for (i = 0; i < size; i++)
  103. middle[i] = GARBAGE;
  104. for (i = 0; i < BORDER_SIZE; i++)
  105. back_border[i] = BORDER;
  106.  
  107. // Update the global static variable showing how much memory is now used.
  108. memory_used_now += size;
  109.  
  110. return middle;
  111. }
  112.  
  113. void operator delete(void* p)
  114. {
  115. char *whole_block; // Pointer to the entire block that we get from heap
  116. size_t *size_spot; // Spot in the block where to store a copy of size
  117. char *front_border; // The border bytes in front of the user's memory
  118. char *middle; // The memory to be given to the calling program
  119. char *back_border; // The border bytes at the back of the user's memory
  120. size_t i; // Loop control variable
  121. size_t size; // Size of the block being returned
  122. bool corrupt; // Set to true if the border was corrupted
  123.  
  124. // Figure out the start of the pieces of the block, and the size.
  125. whole_block = ((char *) (p)) - BORDER_SIZE;
  126. size_spot = (size_t *) whole_block;
  127. size = *size_spot;
  128. front_border = (char *) (whole_block + sizeof(size_t));
  129. middle = (char *) (whole_block + BORDER_SIZE);
  130. back_border = middle + size;
  131.  
  132. // Check the borders for the BORDER character.
  133. corrupt = false;
  134. for (i = 0; i < BORDER_SIZE - sizeof(size_t); i++)
  135. if (front_border[i] != BORDER)
  136. corrupt = true;
  137. for (i = 0; i < BORDER_SIZE; i++)
  138. if (back_border[i] != BORDER)
  139. corrupt = true;
  140.  
  141. if (corrupt)
  142. {
  143. cout << "The delete operator has detected that the program wrote\n";
  144. cout << "beyond the ends of a block of memory that was allocated\n";
  145. cout << "by the new operator. Program will be halted." << endl;
  146. exit(0);
  147. }
  148. else
  149. {
  150. // Fill memory with garbage in case program tries to use it
  151. // even after the delete.
  152. for (i = 0; i < size + 2*BORDER_SIZE; i++)
  153. whole_block[i] = GARBAGE;
  154. free(whole_block);
  155. memory_used_now -= size;
  156. }
  157.  
  158. }
  159.  
  160.  
  161. // **************************************************************************
  162. // bool correct(PriorityQueue& test, size_t n, int items[])
  163. // Postcondition: Some tests have been run on the test priority queue.
  164. // If this priority queue has n items, and these items are items[0]
  165. // through items[n-1] (in that order), then the function has printed
  166. // "Test passed." to cout and returned true. Otherwise the function
  167. // has printed "Test failed." to cout and returned false.
  168. // NOTE: If all tests were passed, then the test PriorityQueue has
  169. // also been emptied.
  170. // **************************************************************************
  171. bool correct(PriorityQueue& test, size_t n, int items[])
  172. // Postcondition: Some tests have been run on the test priority queue.
  173. // If this priority queue has n items, and these items are items[0]
  174. // through items[n-1] (in that order), then the function has printed
  175. // "Test passed." to cout and returned true. Otherwise the function
  176. // has printed "Test failed." to cout and returned false.
  177. // NOTE: If all tests were passed, then the test PriorityQueue has
  178. // also been emptied.
  179. {
  180. size_t i;
  181. bool answer = true;
  182. if (test.size( ) != n)
  183. answer = false;
  184. else if (test.is_empty( ) != (n == 0))
  185. answer = false;
  186. else
  187. for (i = 0; answer && (i < n); i++)
  188. if (items[i] != test.get_front( ))
  189. answer = false;
  190. cout << (answer ? "Test passed.\n" : "Test failed.\n") << endl;
  191. return answer;
  192. }
  193.  
  194. int test1( )
  195. // Postcondition: A handful of simple tests have been run on the
  196. // PriorityQueue data type. If all tests are passed, then the function
  197. // returns POINTS[1]. Otherwise the function returns zero.
  198. {
  199. // A random test will be done with TEST_SIZE elements. Each
  200. // element will have a priority below PRIORITY_LIMIT.
  201. const size_t TEST_SIZE = 400;
  202. const unsigned int PRIORITY_LIMIT = 100;
  203.  
  204. PriorityQueue test;
  205. int items[8] = { 100, 200, 3, 4, 5, 6, 8, 7 };
  206. int occurs[PRIORITY_LIMIT];
  207. int rand_items[TEST_SIZE];
  208. char test_letter = 'A';
  209. int i;
  210. unsigned int priority;
  211.  
  212. cout << test_letter++ << ". ";
  213. cout << "Testing size and is_empty for an empty priority queue.";
  214. cout << endl;
  215. if (!correct(test, 0, items)) return 0;
  216.  
  217. cout << test_letter++ << ". ";
  218. cout << "Adding one item to the queue, and then testing\n";
  219. cout << " is_empty, size, and get_front.";
  220. cout << endl;
  221. test.insert(100, 1);
  222. if (!correct(test, 1, items)) return 0;
  223.  
  224. cout << test_letter++ << ". ";
  225. cout << "Inserting two items (first has higher priority).\n";
  226. cout << " Then checking that both items come out correctly.";
  227. cout << endl;
  228. test.insert(100, 10);
  229. test.insert(200, 5);
  230. if (!correct(test, 2, items)) return 0;
  231.  
  232. cout << test_letter++ << ". ";
  233. cout << "Inserting two items (second has higher priority).\n";
  234. cout << " Then checking that both items come out correctly.";
  235. cout << endl;
  236. test.insert(200, 5);
  237. test.insert(100, 10);
  238. if (!correct(test, 2, items)) return 0;
  239.  
  240. cout << test_letter++ << ". ";
  241. cout << "Inserting eight items with priorities of\n";
  242. cout << " 8, 10, 3, 3, 8, 6, 10, 6 (in that order)\n";
  243. cout << " Then checking that all items come out correctly.";
  244. cout << endl;
  245. test.insert(3, 8);
  246. test.insert(100, 10);
  247. test.insert(8, 3);
  248. test.insert(7, 3);
  249. test.insert(4, 8);
  250. test.insert(5, 6);
  251. test.insert(200, 10);
  252. test.insert(6, 6);
  253. if (!correct(test, 8, items)) return 0;
  254.  
  255. cout << test_letter++ << ". ";
  256. cout << "Inserting " << TEST_SIZE << " random items with random\n";
  257. cout << " priorities, and checking that all items come out right.";
  258. cout << endl;
  259. for (priority = 0; priority < PRIORITY_LIMIT; priority++)
  260. occurs[priority] = 0;
  261. for (i = 0; i < TEST_SIZE; i++)
  262. {
  263. // Insert a bunch of random items, using items themselves as priorities
  264. priority = (unsigned) (rand( ) % 100);
  265. test.insert((int) priority, priority);
  266. occurs[priority]++;
  267. }
  268. priority = PRIORITY_LIMIT-1;
  269. for (i = 0; i < TEST_SIZE; i++)
  270. {
  271. while (occurs[priority] == 0)
  272. priority--;
  273. rand_items[i] = (int) priority;
  274. occurs[priority]--;
  275. }
  276. if (!correct(test, TEST_SIZE, rand_items)) return 0;
  277.  
  278. return POINTS[1];
  279. }
  280.  
  281.  
  282. // **************************************************************************
  283. // int test2( )
  284. // Tries to find a heap leak in the assignment operator or the
  285. // destructor.
  286. // Returns POINTS[2] if no leaks are found. Otherwise returns 0.
  287. // **************************************************************************
  288. int test2( )
  289. {
  290. const size_t TEST_SIZE = 200;
  291. PriorityQueue test, empty;
  292. PriorityQueue* pq_ptr;
  293. size_t base_usage;
  294. int i;
  295. int next;
  296.  
  297. cout << "Checking for possible heap leak." << endl;
  298. cout << "This could occur if the assignment operator, get_front, or\n";
  299. cout << "the destructor does not correctly release memory.\n";
  300.  
  301. // Test get_front for a heap leak
  302. cout << "Testing for heap leak in get_front..." << flush;
  303. base_usage = memory_used_now;
  304. for (i = 0; i < TEST_SIZE; i++)
  305. test.insert(i, unsigned(i));
  306. for (i = 0; i < TEST_SIZE; i++)
  307. next = test.get_front( );
  308. if (memory_used_now != base_usage)
  309. {
  310. cout << "\n Test failed. Probable heap leak in get_front." << endl;
  311. return 0;
  312. }
  313. else
  314. cout << "passed." << endl;
  315.  
  316. // Test for heap leak in destructor.
  317. cout << "Testing for heap leak in destructor ... " << flush;
  318. pq_ptr = new PriorityQueue;
  319. for (i = 0; i < TEST_SIZE; i++)
  320. pq_ptr->insert(i, unsigned(i));
  321. delete pq_ptr;
  322. if (memory_used_now != base_usage)
  323. {
  324. cout << "\n Test failed. Possible heap leak in copy constructor." << endl;
  325. return 0;
  326. }
  327. else
  328. cout << "passed." << endl;
  329.  
  330. // Test for heap leak in assignment operator.
  331. cout << "Testing for heap leak in assignment operator ... " << flush;
  332. for (i = 0; i < TEST_SIZE; i++)
  333. test.insert(i, unsigned(i));
  334. test = empty; // Should return test's list to the heap
  335. if (memory_used_now != base_usage)
  336. {
  337. cout << "\n Test failed. Possible heap leak in assignment operator." << endl;
  338. return 0;
  339. }
  340. else
  341. cout << "passed." << endl;
  342.  
  343. cout << "No heap leaks found." << endl;
  344. return POINTS[2];
  345. }
  346.  
  347. int test3( )
  348. // Postcondition: The PriorityQueue's copy constructor has been tested.
  349. // The return value is 10 if the test was passed. Otherwise the return
  350. // value is zero.
  351. {
  352. PriorityQueue test;
  353. int items[4] = { 1, 2, 3, 4 };
  354.  
  355. cout << "A. Testing that copy constructor works okay for empty queue...";
  356. cout << flush;
  357. PriorityQueue copy1(test);
  358. if (!correct(copy1, 0, items)) return 0;
  359.  
  360. cout << "B. Testing copy constructor with 4-item queue...";
  361. cout << flush;
  362. test.insert(1, 100);
  363. test.insert(2, 50);
  364. test.insert(3, 25);
  365. test.insert(4, 10);
  366. PriorityQueue copy2(test);
  367. test.insert(5, 80); // Alter the original, but not the copy
  368. if (!correct(copy2, 4, items)) return 0;
  369.  
  370. cout << "Copy constructor seems okay." << endl;
  371. return POINTS[3];
  372. }
  373.  
  374. int test4( )
  375. // Postcondition: The PriorityQueue's assignment operator has been tested.
  376. // The return value is 10 if the test was passed. Otherwise the return
  377. // value is zero.
  378. {
  379. PriorityQueue test;
  380. int items[4] = { 1, 2, 3, 4 };
  381. char *oldbytes = new char[sizeof(PriorityQueue)];
  382. char *newbytes = new char[sizeof(PriorityQueue)];
  383. int i;
  384.  
  385. cout << "A. Testing that assignment operator works okay for empty queue...";
  386. cout << flush;
  387. PriorityQueue copy1;
  388. copy1.insert(1,1);
  389. copy1 = test;
  390. if (!correct(copy1, 0, items)) return 0;
  391.  
  392. cout << "B. Testing assignment operator with 4-item queue...";
  393. cout << flush;
  394. test.insert(1, 100);
  395. test.insert(2, 50);
  396. test.insert(3, 25);
  397. test.insert(4, 10);
  398. PriorityQueue copy2;
  399. copy2 = test;
  400. test.insert(5, 80); // Alter the original, but not the copy
  401. if (!correct(copy2, 4, items)) return 0;
  402.  
  403. cout << "C. Testing assignment operator for a self-assignment...";
  404. cout << flush;
  405. memcpy(oldbytes, &test, sizeof(PriorityQueue));
  406. test = test;
  407. memcpy(newbytes, &test, sizeof(PriorityQueue));
  408. for (i=0; i < sizeof(PriorityQueue); i++)
  409. if (oldbytes[i] != newbytes[i])
  410. {
  411. cout << "failed." << endl;
  412. return 0;
  413. }
  414. cout << "passed.\n";
  415.  
  416. cout << "Assignment operator seems okay." << endl;
  417. return POINTS[4];
  418. }
  419.  
  420.  
  421. int run_a_test(int number, const char message[], int test_function( ), int max)
  422. {
  423. int result;
  424.  
  425. cout << endl << "START OF TEST " << number << ":" << endl;
  426. cout << message << " (" << max << " points)." << endl;
  427. result = test_function( );
  428. if (result > 0)
  429. {
  430. cout << "Test " << number << " got " << result << " points";
  431. cout << " out of a possible " << max << "." << endl;
  432. }
  433. else
  434. cout << "Test " << number << " failed." << endl;
  435. cout << "END OF TEST " << number << "." << endl << endl;
  436.  
  437. return result;
  438. }
  439.  
  440. // **************************************************************************
  441. // int main( )
  442. // The main program calls all tests and prints the sum of all points
  443. // earned from the tests.
  444. // **************************************************************************
  445. int main( )
  446. {
  447. int sum = 0;
  448.  
  449. cout << "Running " << DESCRIPTION[0] << endl;
  450.  
  451. sum += run_a_test(1, DESCRIPTION[1], test1, POINTS[1]);
  452. sum += run_a_test(2, DESCRIPTION[2], test2, POINTS[2]);
  453. sum += run_a_test(3, DESCRIPTION[3], test3, POINTS[3]);
  454. sum += run_a_test(4, DESCRIPTION[4], test4, POINTS[4]);
  455.  
  456. cout << "If you submit this PriorityQueue now, you will have\n";
  457. cout << sum << " points out of the " << POINTS[0];
  458. cout << " points from this test program.\n";
  459.  
  460. system("PAUSE");
  461. return EXIT_SUCCESS;
  462.  
  463. }

Report this snippet  

You need to login to post a comment.