1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <cppunit/TestAssert.h>
21 #include <cppunit/TestFixture.h>
22 #include <cppunit/extensions/HelperMacros.h>
23 
24 //#define TIMELOG for measuring performance
25 
26 #include <bparr.hxx>
27 
28 using namespace std;
29 
30 namespace /* private */
31 {
32     const sal_uLong NUM_ENTRIES = 10;
33 
34     class BigPtrEntryMock : public BigPtrEntry
35     {
36     public:
BigPtrEntryMock(sal_uLong count)37         explicit BigPtrEntryMock(sal_uLong count) : count_(count)
38         {
39         }
40 
getCount() const41         sal_uLong getCount() const
42         {
43             return count_;
44         }
45 
Position() const46         sal_uLong Position() const
47         {
48             return GetPos();
49         }
50 
51     private:
52         sal_uLong count_;
53     };
54 
fillBigPtrArray(BigPtrArray & bparr,sal_uLong numEntries)55     void fillBigPtrArray(BigPtrArray& bparr, sal_uLong numEntries)
56     {
57         for (sal_uLong i = 0; i < numEntries; i++)
58             bparr.Insert(new BigPtrEntryMock(i), bparr.Count());
59     }
60 
checkElementPositions(const BigPtrArray & bparr)61     bool checkElementPositions(const BigPtrArray& bparr)
62     {
63         for (sal_uLong i = 0; i < bparr.Count(); i++)
64         {
65             if (static_cast<BigPtrEntryMock*>(bparr[i])->Position() != i)
66                 return false;
67         }
68         return true;
69     }
70 
releaseBigPtrArrayContent(BigPtrArray const & bparr)71     void releaseBigPtrArrayContent(BigPtrArray const & bparr)
72     {
73         for (sal_uLong i = 0; i < bparr.Count(); i++)
74             delete bparr[i];
75     }
76 }
77 
78 class BigPtrArrayUnittest : public CppUnit::TestFixture
79 {
80 public:
81 
BigPtrArrayUnittest()82     BigPtrArrayUnittest()
83     {
84     }
85 
86     /** Test constructor/destructor
87         The size of the BigPtrArray
88         aka the 'Count' should be 0
89         initially.
90     */
test_ctor()91     void test_ctor()
92     {
93         BigPtrArray bparr;
94 
95         CPPUNIT_ASSERT_EQUAL_MESSAGE
96         (
97             "BigPtrArray ctor failed",
98             static_cast<sal_uLong>(0), bparr.Count()
99         );
100     }
101 
test_insert_entries_at_front()102     void test_insert_entries_at_front()
103     {
104         BigPtrArray bparr;
105 
106         for (sal_uLong i = 0; i < NUM_ENTRIES; i++)
107         {
108             sal_uLong oldCount = bparr.Count();
109             bparr.Insert(new BigPtrEntryMock(i), 0);
110             CPPUNIT_ASSERT_EQUAL_MESSAGE
111             (
112                 "test_insert_entries_at_front failed",
113                 oldCount + 1, bparr.Count()
114             );
115         }
116 
117         for (sal_uLong i = 0, j = NUM_ENTRIES - 1; i < NUM_ENTRIES; i++, j--)
118         {
119             CPPUNIT_ASSERT_EQUAL_MESSAGE
120             (
121                 "test_insert_entries_at_front failed",
122                 j, static_cast<BigPtrEntryMock*>(bparr[i])->getCount()
123             );
124         }
125 
126         CPPUNIT_ASSERT_MESSAGE
127         (
128             "test_insert_entries_at_front failed",
129             checkElementPositions(bparr)
130         );
131 
132         releaseBigPtrArrayContent(bparr);
133     }
134 
test_insert_entries_in_the_middle()135     void test_insert_entries_in_the_middle()
136     {
137         BigPtrArray bparr;
138 
139         fillBigPtrArray(bparr, NUM_ENTRIES);
140 
141         sal_uLong oldCount = bparr.Count();
142 
143         bparr.Insert(new BigPtrEntryMock(NUM_ENTRIES), bparr.Count() / 2);
144 
145         CPPUNIT_ASSERT_MESSAGE
146         (
147             "test_insert_entries_in_the_middle failed",
148             (oldCount + 1 == bparr.Count() && static_cast<BigPtrEntryMock*>(bparr[bparr.Count() / 2])->getCount() == NUM_ENTRIES)
149         );
150 
151         CPPUNIT_ASSERT_MESSAGE
152         (
153             "test_insert_entries_in_the_middle failed",
154             checkElementPositions(bparr)
155         );
156 
157         releaseBigPtrArrayContent(bparr);
158     }
159 
test_insert_at_already_used_index()160     void test_insert_at_already_used_index()
161     {
162         BigPtrArray bparr;
163 
164         fillBigPtrArray(bparr, NUM_ENTRIES);
165 
166         const sal_uLong oldCount = bparr.Count();
167 
168         // insert 5 elements
169         for (sal_uLong i = 0, j = 30; i < 5; i++, j++)
170             bparr.Insert(new BigPtrEntryMock(j), i);
171 
172         CPPUNIT_ASSERT_EQUAL_MESSAGE
173         (
174             "test_insert_at_already_used_index failed",
175             oldCount + 5, bparr.Count()
176         );
177 
178         // now, first 5 elements have counts: 30,31,..34
179         // next 10 elements have counts: 0,1,..9
180         for (sal_uLong i = 0, j = 30; i < bparr.Count(); i++, j++)
181         {
182             CPPUNIT_ASSERT_EQUAL_MESSAGE
183             (
184                 "test_insert_at_already_used_index failed",
185                 (i < 5 ? j : i - 5), static_cast<BigPtrEntryMock*>(bparr[i])->getCount()
186             );
187         }
188 
189         CPPUNIT_ASSERT_MESSAGE
190         (
191             "test_insert_at_already_used_index failed",
192             checkElementPositions(bparr)
193         );
194 
195         releaseBigPtrArrayContent(bparr);
196     }
197 
test_insert_at_end()198     void test_insert_at_end()
199     {
200         BigPtrArray bparr;
201 
202         fillBigPtrArray(bparr, NUM_ENTRIES);
203 
204         sal_uLong oldCount = bparr.Count();
205         bparr.Insert(new BigPtrEntryMock(NUM_ENTRIES), bparr.Count());
206 
207         CPPUNIT_ASSERT_MESSAGE
208         (
209             "test_insert_at_end failed",
210             (oldCount + 1 == bparr.Count() && static_cast<BigPtrEntryMock*>(bparr[bparr.Count()-1])->getCount() == NUM_ENTRIES)
211         );
212 
213         CPPUNIT_ASSERT_MESSAGE
214         (
215             "test_insert_at_end failed",
216             checkElementPositions(bparr)
217         );
218 
219         releaseBigPtrArrayContent(bparr);
220     }
221 
test_remove_at_front()222     void test_remove_at_front()
223     {
224         BigPtrArray bparr;
225 
226         fillBigPtrArray(bparr, NUM_ENTRIES);
227 
228         for (sal_uLong i = 0; i < NUM_ENTRIES; i++)
229         {
230             sal_uLong oldCount = bparr.Count();
231 
232             delete bparr[0]; // release content
233             bparr.Remove(0); // remove item from container
234 
235             CPPUNIT_ASSERT_EQUAL_MESSAGE
236             (
237                 "test_remove_at_front failed (wrong count)",
238                 oldCount - 1, bparr.Count()
239             );
240 
241             for (sal_uLong j = 0, k = i + 1; j < bparr.Count(); j++, k++)
242             {
243                 CPPUNIT_ASSERT_EQUAL_MESSAGE
244                 (
245                     "test_remove_at_front failed",
246                     k, static_cast<BigPtrEntryMock*>(bparr[j])->getCount()
247                 );
248             }
249 
250             CPPUNIT_ASSERT_MESSAGE
251             (
252                 "test_remove_at_front failed",
253                 checkElementPositions(bparr)
254             );
255         }
256     }
257 
test_remove_at_back()258     void test_remove_at_back()
259     {
260         BigPtrArray bparr;
261 
262         fillBigPtrArray(bparr, NUM_ENTRIES);
263 
264         for (int i = NUM_ENTRIES - 1; i >= 0; i--)
265         {
266             sal_uLong oldCount = bparr.Count();
267             delete bparr[i];
268             bparr.Remove(i);
269 
270             CPPUNIT_ASSERT_EQUAL_MESSAGE
271             (
272                 "test_remove_at_back failed (wrong count)",
273                 (oldCount - 1), bparr.Count()
274             );
275 
276             for (sal_uLong j = 0; j < bparr.Count(); j++)
277             {
278                 CPPUNIT_ASSERT_EQUAL_MESSAGE
279                 (
280                     "test_remove_at_back failed",
281                     j, static_cast<BigPtrEntryMock*>(bparr[j])->getCount()
282                 );
283             }
284 
285             CPPUNIT_ASSERT_MESSAGE
286             (
287                 "test_remove_at_back failed",
288                 checkElementPositions(bparr)
289             );
290         }
291     }
292 
test_remove_in_the_middle()293     void test_remove_in_the_middle()
294     {
295         BigPtrArray bparr;
296 
297         fillBigPtrArray(bparr, NUM_ENTRIES);
298 
299         while (bparr.Count())
300         {
301             sal_uLong oldCount = bparr.Count();
302             sal_uLong oldElement = static_cast<BigPtrEntryMock*>(bparr[bparr.Count() / 2])->getCount();
303 
304             delete bparr[bparr.Count() / 2];
305             bparr.Remove(bparr.Count() / 2);
306 
307             CPPUNIT_ASSERT_EQUAL_MESSAGE
308             (
309                 "test_remove_in_the_middle failed (wrong count)",
310                 oldCount - 1, bparr.Count()
311             );
312 
313             for (sal_uLong i = 0; i < bparr.Count(); i++)
314             {
315                 CPPUNIT_ASSERT_MESSAGE
316                 (
317                     "test_remove_in_the_middle failed",
318                     static_cast<BigPtrEntryMock*>(bparr[i])->getCount() != oldElement
319                 );
320             }
321 
322             CPPUNIT_ASSERT_MESSAGE
323             (
324                 "test_remove_in_the_middle failed",
325                 checkElementPositions(bparr)
326             );
327         }
328     }
329 
test_remove_multiple_elements_at_once()330     void test_remove_multiple_elements_at_once()
331     {
332         BigPtrArray bparr;
333 
334         fillBigPtrArray(bparr, NUM_ENTRIES);
335 
336         while(bparr.Count())
337         {
338             sal_uLong nRemove = std::min<sal_uLong>(bparr.Count(), 3);
339             sal_uLong oldCount = bparr.Count();
340 
341             for (sal_uLong i = 0; i < nRemove; i++)
342                 delete bparr[i];
343 
344             bparr.Remove(0, nRemove);
345 
346             CPPUNIT_ASSERT_EQUAL_MESSAGE
347             (
348                 "test_remove_multiple_elements_at_once failed",
349                 oldCount - nRemove, bparr.Count()
350             );
351 
352             CPPUNIT_ASSERT_MESSAGE
353             (
354                 "test_remove_multiple_elements_at_once failed",
355                 checkElementPositions(bparr)
356             );
357         }
358     }
359 
test_remove_all_elements_at_once()360     void test_remove_all_elements_at_once()
361     {
362         BigPtrArray bparr;
363 
364         fillBigPtrArray(bparr, NUM_ENTRIES);
365 
366         releaseBigPtrArrayContent(bparr);
367         bparr.Remove(0, bparr.Count());
368 
369         CPPUNIT_ASSERT_EQUAL_MESSAGE
370         (
371             "test_remove_all_elements_at_once failed",
372             static_cast<sal_uLong>(0), bparr.Count()
373         );
374     }
375 
test_move_elements_from_lower_to_higher_pos()376     void test_move_elements_from_lower_to_higher_pos()
377     {
378         BigPtrArray bparr;
379 
380         fillBigPtrArray(bparr, NUM_ENTRIES);
381 
382         for (sal_uLong i = 0; i < NUM_ENTRIES - 1; i++)
383         {
384             bparr.Move(i, i + 2);
385         }
386 
387         for (sal_uLong i = 0; i < (NUM_ENTRIES - 1); i++)
388         {
389             CPPUNIT_ASSERT_EQUAL_MESSAGE
390             (
391                 "test_move_elements_from_lower_to_higher_pos failed",
392                 (i + 1), static_cast<BigPtrEntryMock*>(bparr[i])->getCount()
393             );
394         }
395 
396         CPPUNIT_ASSERT_EQUAL_MESSAGE
397         (
398             "test_move_elements_from_lower_to_higher_pos failed",
399             static_cast<sal_uLong>(0), static_cast<BigPtrEntryMock*>(bparr[NUM_ENTRIES -1])->getCount()
400         );
401 
402         CPPUNIT_ASSERT_MESSAGE
403         (
404             "test_move_elements_from_lower_to_higher_pos failed",
405             checkElementPositions(bparr)
406         );
407 
408         releaseBigPtrArrayContent(bparr);
409     }
410 
test_move_elements_from_higher_to_lower_pos()411     void test_move_elements_from_higher_to_lower_pos()
412     {
413         BigPtrArray bparr;
414 
415         fillBigPtrArray(bparr, NUM_ENTRIES);
416 
417         for (int i = NUM_ENTRIES - 1; i >= 1; i--)
418         {
419             bparr.Move(i, i - 1);
420         }
421 
422         CPPUNIT_ASSERT_EQUAL_MESSAGE
423         (
424             "test_move_elements_from_higher_to_lower_pos failed",
425             (NUM_ENTRIES - 1), static_cast<BigPtrEntryMock*>(bparr[0])->getCount()
426         );
427 
428         for (sal_uLong i = 1; i < NUM_ENTRIES; i++)
429         {
430             CPPUNIT_ASSERT_EQUAL_MESSAGE
431             (
432                 "test_move_elements_from_higher_to_lower_pos failed",
433                 (i - 1), static_cast<BigPtrEntryMock*>(bparr[i])->getCount()
434             );
435         }
436 
437         CPPUNIT_ASSERT_MESSAGE
438         (
439             "test_move_elements_from_higher_to_lower_pos failed",
440             checkElementPositions(bparr)
441         );
442 
443         releaseBigPtrArrayContent(bparr);
444     }
445 
test_move_to_same_position()446     void test_move_to_same_position()
447     {
448         BigPtrArray bparr;
449 
450         fillBigPtrArray(bparr, NUM_ENTRIES);
451 
452         for (sal_uLong i = 0; i < NUM_ENTRIES; i++)
453         {
454             bparr.Move(i, i);
455         }
456 
457         for (sal_uLong i = 0; i < NUM_ENTRIES; i++)
458         {
459             CPPUNIT_ASSERT_EQUAL_MESSAGE
460             (
461                 "test_move_to_same_position failed",
462                 i, static_cast<BigPtrEntryMock*>(bparr[i])->getCount()
463             );
464         }
465 
466         CPPUNIT_ASSERT_MESSAGE
467         (
468             "test_move_to_same_position failed",
469             checkElementPositions(bparr)
470         );
471 
472         releaseBigPtrArrayContent(bparr);
473     }
474 
test_replace_elements()475     void test_replace_elements()
476     {
477         BigPtrArray bparr;
478 
479         fillBigPtrArray(bparr, NUM_ENTRIES);
480 
481         for (sal_uLong i = 0, j = NUM_ENTRIES - 1; i < NUM_ENTRIES; i++, j--)
482         {
483             delete bparr[i];
484             bparr.Replace(i, new BigPtrEntryMock(j));
485         }
486 
487         for (sal_uLong i = 0; i < NUM_ENTRIES; i++)
488         {
489             CPPUNIT_ASSERT_EQUAL_MESSAGE
490             (
491                 "test_replace_elements failed",
492                 (NUM_ENTRIES - i - 1), static_cast<BigPtrEntryMock*>(bparr[i])->getCount()
493             );
494         }
495 
496         CPPUNIT_ASSERT_MESSAGE
497         (
498             "test_replace_elements failed",
499             checkElementPositions(bparr)
500         );
501 
502         releaseBigPtrArrayContent(bparr);
503     }
504 
505     CPPUNIT_TEST_SUITE(BigPtrArrayUnittest);
506     CPPUNIT_TEST(test_ctor);
507     CPPUNIT_TEST(test_insert_entries_at_front);
508     CPPUNIT_TEST(test_insert_entries_in_the_middle);
509     CPPUNIT_TEST(test_insert_at_already_used_index);
510     CPPUNIT_TEST(test_insert_at_end);
511     CPPUNIT_TEST(test_remove_at_front);
512     CPPUNIT_TEST(test_remove_at_back);
513     CPPUNIT_TEST(test_remove_in_the_middle);
514     CPPUNIT_TEST(test_remove_multiple_elements_at_once);
515     CPPUNIT_TEST(test_remove_all_elements_at_once);
516     CPPUNIT_TEST(test_move_elements_from_lower_to_higher_pos);
517     CPPUNIT_TEST(test_move_elements_from_higher_to_lower_pos);
518     CPPUNIT_TEST(test_move_to_same_position);
519     CPPUNIT_TEST(test_replace_elements);
520     CPPUNIT_TEST_SUITE_END();
521 };
522 
523 #if defined TIMELOG
524 
525 const char* const START = "START: ";
526 const char* const END = "END: ";
527 
528 class PerformanceTracer
529 {
530 public:
531 
532 public:
PerformanceTracer(const string & methodName)533     explicit PerformanceTracer(const string& methodName) :
534         startString_(START),
535         endString_(END)
536     {
537         startString_ += methodName;
538         endString_ += methodName;
539     }
540 
~PerformanceTracer()541     ~PerformanceTracer()
542     {
543     }
544 
545 private:
546     string startString_;
547     string endString_;
548 };
549 
550 class BigPtrArrayPerformanceTest : public CppUnit::TestFixture
551 {
552 public:
BigPtrArrayPerformanceTest()553     BigPtrArrayPerformanceTest()
554     {
555     }
556 
test_insert_at_end_1000()557     void test_insert_at_end_1000()
558     { test_insert_at_end("1000"); }
559 
test_insert_at_end_10000()560     void test_insert_at_end_10000()
561     { test_insert_at_end("10000"); }
562 
test_insert_at_end_100000()563     void test_insert_at_end_100000()
564     { test_insert_at_end("100000"); }
565 
test_insert_at_end_1000000()566     void test_insert_at_end_1000000()
567     { test_insert_at_end("1000000"); }
568 
test_insert_at_front_1000()569     void test_insert_at_front_1000()
570     { test_insert_at_front("1000"); }
571 
test_insert_at_front_10000()572     void test_insert_at_front_10000()
573     { test_insert_at_front("10000"); }
574 
test_insert_at_front_100000()575     void test_insert_at_front_100000()
576     { test_insert_at_front("100000"); }
577 
test_insert_at_front_1000000()578     void test_insert_at_front_1000000()
579     { test_insert_at_front("1000000"); }
580 
581     CPPUNIT_TEST_SUITE(BigPtrArrayPerformanceTest);
582     CPPUNIT_TEST(test_insert_at_end_1000);
583     CPPUNIT_TEST(test_insert_at_end_10000);
584     CPPUNIT_TEST(test_insert_at_end_100000);
585     CPPUNIT_TEST(test_insert_at_end_1000000);
586     CPPUNIT_TEST(test_insert_at_front_1000);
587     CPPUNIT_TEST(test_insert_at_front_10000);
588     CPPUNIT_TEST(test_insert_at_front_100000);
589     CPPUNIT_TEST(test_insert_at_front_1000000);
590     CPPUNIT_TEST_SUITE_END();
591 
592 private:
test_insert_at_end(const char * numElements)593     void test_insert_at_end(const char* numElements)
594     {
595         OStringBuffer buff("test_insert_at_end ");
596         buff.append(numElements);
597         int n = atoi(numElements);
598         PerformanceTracer tracer(buff.getStr());
599         BigPtrArray bparr;
600         for (int i = 0; i < n; i++)
601             bparr.Insert(new BigPtrEntryMock(i), bparr.Count());
602 
603         releaseBigPtrArrayContent(bparr);
604     }
605 
test_insert_at_front(const char * numElements)606     void test_insert_at_front(const char* numElements)
607     {
608         OStringBuffer buff("test_insert_at_front ");
609         buff.append(numElements);
610         int n = atoi(numElements);
611         PerformanceTracer tracer(buff.getStr());
612         BigPtrArray bparr;
613         for (int i = 0; i < n; i++)
614             bparr.Insert(new BigPtrEntryMock(i), 0);
615 
616         releaseBigPtrArrayContent(bparr);
617     }
618 };
619 
620 #endif
621 
622 // register test suites
623 CPPUNIT_TEST_SUITE_REGISTRATION(BigPtrArrayUnittest);
624 #ifdef TIMELOG
625 CPPUNIT_TEST_SUITE_REGISTRATION(BigPtrArrayPerformanceTest);
626 #endif
627 
628 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
629