1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include <assert.h>
40 : #include <stdio.h>
41 : #include "nsCOMPtr.h"
42 : #include "nsAutoPtr.h"
43 : #include "nsISupports.h"
44 :
45 : #define NS_FOO_IID \
46 : { 0x6f7652e0, 0xee43, 0x11d1, \
47 : { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
48 :
49 : class Foo : public nsISupports
50 : {
51 : public:
52 10 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_FOO_IID)
53 :
54 : public:
55 : Foo();
56 : // virtual dtor because Bar uses our Release()
57 : virtual ~Foo();
58 :
59 : NS_IMETHOD_(nsrefcnt) AddRef();
60 : NS_IMETHOD_(nsrefcnt) Release();
61 : NS_IMETHOD QueryInterface( const nsIID&, void** );
62 :
63 : static void print_totals();
64 :
65 : private:
66 : unsigned int refcount_;
67 :
68 : static unsigned int total_constructions_;
69 : static unsigned int total_destructions_;
70 : };
71 :
72 : NS_DEFINE_STATIC_IID_ACCESSOR(Foo, NS_FOO_IID)
73 :
74 : class Bar;
75 :
76 : // some types I'll need
77 : typedef unsigned long NS_RESULT;
78 :
79 : // some functions I'll need (and define below)
80 : nsresult CreateFoo( void** );
81 : nsresult CreateBar( void** result );
82 : void AnFooPtrPtrContext( Foo** );
83 : void AnISupportsPtrPtrContext( nsISupports** );
84 : void AVoidPtrPtrContext( void** );
85 : void set_a_Foo( nsRefPtr<Foo>* result );
86 : nsRefPtr<Foo> return_a_Foo();
87 :
88 :
89 :
90 :
91 : unsigned int Foo::total_constructions_;
92 : unsigned int Foo::total_destructions_;
93 :
94 : class test_message
95 : {
96 : public:
97 1 : test_message()
98 : {
99 1 : printf("BEGIN unit tests for |nsRefPtr|, compiled " __DATE__ "\n");
100 1 : }
101 :
102 1 : ~test_message()
103 : {
104 1 : Foo::print_totals();
105 1 : printf("END unit tests for |nsRefPtr|.\n");
106 1 : }
107 : };
108 :
109 1 : test_message gTestMessage;
110 :
111 :
112 : /*
113 : ...
114 : */
115 :
116 : void
117 3 : Foo::print_totals()
118 : {
119 : printf("total constructions/destructions --> %d/%d\n",
120 3 : total_constructions_, total_destructions_);
121 3 : }
122 :
123 18 : Foo::Foo()
124 18 : : refcount_(0)
125 : {
126 18 : ++total_constructions_;
127 : printf(" new Foo@%p [#%d]\n",
128 18 : static_cast<void*>(this), total_constructions_);
129 18 : }
130 :
131 32 : Foo::~Foo()
132 : {
133 18 : ++total_destructions_;
134 : printf("Foo@%p::~Foo() [#%d]\n",
135 18 : static_cast<void*>(this), total_destructions_);
136 64 : }
137 :
138 : nsrefcnt
139 27 : Foo::AddRef()
140 : {
141 27 : ++refcount_;
142 : printf("Foo@%p::AddRef(), refcount --> %d\n",
143 27 : static_cast<void*>(this), refcount_);
144 27 : return refcount_;
145 : }
146 :
147 : nsrefcnt
148 27 : Foo::Release()
149 : {
150 27 : int newcount = --refcount_;
151 27 : if ( newcount == 0 )
152 18 : printf(">>");
153 :
154 : printf("Foo@%p::Release(), refcount --> %d\n",
155 27 : static_cast<void*>(this), refcount_);
156 :
157 27 : if ( newcount == 0 )
158 : {
159 18 : printf(" delete Foo@%p\n", static_cast<void*>(this));
160 18 : printf("<<Foo@%p::Release()\n", static_cast<void*>(this));
161 18 : delete this;
162 : }
163 :
164 27 : return newcount;
165 : }
166 :
167 : nsresult
168 10 : Foo::QueryInterface( const nsIID& aIID, void** aResult )
169 : {
170 10 : printf("Foo@%p::QueryInterface()\n", static_cast<void*>(this));
171 10 : nsISupports* rawPtr = 0;
172 10 : nsresult status = NS_OK;
173 :
174 10 : if ( aIID.Equals(GetIID()) )
175 10 : rawPtr = this;
176 : else
177 : {
178 0 : nsID iid_of_ISupports = NS_ISUPPORTS_IID;
179 0 : if ( aIID.Equals(iid_of_ISupports) )
180 0 : rawPtr = static_cast<nsISupports*>(this);
181 : else
182 0 : status = NS_ERROR_NO_INTERFACE;
183 : }
184 :
185 10 : NS_IF_ADDREF(rawPtr);
186 10 : *aResult = rawPtr;
187 :
188 10 : return status;
189 : }
190 :
191 : nsresult
192 2 : CreateFoo( void** result )
193 : // a typical factory function (that calls AddRef)
194 : {
195 2 : printf(">>CreateFoo() --> ");
196 2 : Foo* foop = new Foo;
197 2 : printf("Foo@%p\n", static_cast<void*>(foop));
198 :
199 2 : foop->AddRef();
200 2 : *result = foop;
201 :
202 2 : printf("<<CreateFoo()\n");
203 2 : return 0;
204 : }
205 :
206 : void
207 1 : set_a_Foo( nsRefPtr<Foo>* result )
208 : {
209 1 : printf(">>set_a_Foo()\n");
210 1 : assert(result);
211 :
212 2 : nsRefPtr<Foo> foop( do_QueryObject(new Foo) );
213 1 : *result = foop;
214 1 : printf("<<set_a_Foo()\n");
215 1 : }
216 :
217 : nsRefPtr<Foo>
218 1 : return_a_Foo()
219 : {
220 1 : printf(">>return_a_Foo()\n");
221 1 : nsRefPtr<Foo> foop( do_QueryObject(new Foo) );
222 1 : printf("<<return_a_Foo()\n");
223 : return foop;
224 : }
225 :
226 :
227 :
228 :
229 : #define NS_BAR_IID \
230 : { 0x6f7652e1, 0xee43, 0x11d1, \
231 : { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
232 :
233 : class Bar : public Foo
234 : {
235 : public:
236 5 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_BAR_IID)
237 :
238 : public:
239 : Bar();
240 : virtual ~Bar();
241 :
242 : NS_IMETHOD QueryInterface( const nsIID&, void** );
243 : };
244 :
245 : NS_DEFINE_STATIC_IID_ACCESSOR(Bar, NS_BAR_IID)
246 :
247 4 : Bar::Bar()
248 : {
249 4 : printf(" new Bar@%p\n", static_cast<void*>(this));
250 4 : }
251 :
252 12 : Bar::~Bar()
253 : {
254 4 : printf("Bar@%p::~Bar()\n", static_cast<void*>(this));
255 16 : }
256 :
257 : nsresult
258 5 : Bar::QueryInterface( const nsID& aIID, void** aResult )
259 : {
260 5 : printf("Bar@%p::QueryInterface()\n", static_cast<void*>(this));
261 5 : nsISupports* rawPtr = 0;
262 5 : nsresult status = NS_OK;
263 :
264 5 : if ( aIID.Equals(GetIID()) )
265 1 : rawPtr = this;
266 4 : else if ( aIID.Equals(NS_GET_IID(Foo)) )
267 4 : rawPtr = static_cast<Foo*>(this);
268 : else
269 : {
270 0 : nsID iid_of_ISupports = NS_ISUPPORTS_IID;
271 0 : if ( aIID.Equals(iid_of_ISupports) )
272 0 : rawPtr = static_cast<nsISupports*>(this);
273 : else
274 0 : status = NS_ERROR_NO_INTERFACE;
275 : }
276 :
277 5 : NS_IF_ADDREF(rawPtr);
278 5 : *aResult = rawPtr;
279 :
280 5 : return status;
281 : }
282 :
283 :
284 :
285 : nsresult
286 2 : CreateBar( void** result )
287 : // a typical factory function (that calls AddRef)
288 : {
289 2 : printf(">>CreateBar() --> ");
290 2 : Bar* barp = new Bar;
291 2 : printf("Bar@%p\n", static_cast<void*>(barp));
292 :
293 2 : barp->AddRef();
294 2 : *result = barp;
295 :
296 2 : printf("<<CreateBar()\n");
297 2 : return 0;
298 : }
299 :
300 : void
301 1 : AnFooPtrPtrContext( Foo** )
302 : {
303 1 : }
304 :
305 : void
306 1 : AVoidPtrPtrContext( void** )
307 : {
308 1 : }
309 :
310 : void
311 0 : AnISupportsPtrPtrContext( nsISupports** )
312 : {
313 0 : }
314 :
315 : nsresult
316 1 : TestBloat_Raw_Unsafe()
317 : {
318 1 : Bar* barP = 0;
319 1 : nsresult result = CreateBar(reinterpret_cast<void**>(&barP));
320 :
321 1 : if ( barP )
322 : {
323 1 : Foo* fooP = 0;
324 1 : if ( NS_SUCCEEDED( result = barP->QueryInterface(NS_GET_IID(Foo), reinterpret_cast<void**>(&fooP)) ) )
325 : {
326 1 : fooP->print_totals();
327 1 : NS_RELEASE(fooP);
328 : }
329 :
330 1 : NS_RELEASE(barP);
331 : }
332 :
333 1 : return result;
334 : }
335 :
336 :
337 : static
338 : nsresult
339 1 : TestBloat_Smart()
340 : {
341 2 : nsRefPtr<Bar> barP;
342 1 : nsresult result = CreateBar( getter_AddRefs(barP) );
343 :
344 2 : nsRefPtr<Foo> fooP( do_QueryObject(barP, &result) );
345 :
346 1 : if ( fooP )
347 1 : fooP->print_totals();
348 :
349 1 : return result;
350 : }
351 :
352 :
353 :
354 :
355 1 : nsRefPtr<Foo> gFoop;
356 :
357 : int
358 1 : main()
359 : {
360 1 : printf(">>main()\n");
361 :
362 1 : printf("sizeof(nsRefPtr<Foo>) --> %u\n", unsigned(sizeof(nsRefPtr<Foo>)));
363 :
364 1 : TestBloat_Raw_Unsafe();
365 1 : TestBloat_Smart();
366 :
367 :
368 : {
369 1 : printf("\n### Test 1: will a |nsCOMPtr| call |AddRef| on a pointer assigned into it?\n");
370 2 : nsRefPtr<Foo> foop( do_QueryObject(new Foo) );
371 :
372 1 : printf("\n### Test 2: will a |nsCOMPtr| |Release| its old pointer when a new one is assigned in?\n");
373 1 : foop = do_QueryObject(new Foo);
374 :
375 : // [Shouldn't compile] Is it a compile time error to try to |AddRef| by hand?
376 : //foop->AddRef();
377 :
378 : // [Shouldn't compile] Is it a compile time error to try to |Release| be hand?
379 : //foop->Release();
380 :
381 : // [Shouldn't compile] Is it a compile time error to try to |delete| an |nsCOMPtr|?
382 : //delete foop;
383 :
384 1 : printf("\n### Test 3: can you |AddRef| if you must?\n");
385 1 : static_cast<Foo*>(foop)->AddRef();
386 :
387 1 : printf("\n### Test 4: can you |Release| if you must?\n");
388 1 : static_cast<Foo*>(foop)->Release();
389 :
390 1 : printf("\n### Test 5: will a |nsCOMPtr| |Release| when it goes out of scope?\n");
391 : }
392 :
393 : {
394 1 : printf("\n### Test 6: will a |nsCOMPtr| call the correct destructor?\n");
395 1 : nsRefPtr<Foo> foop( do_QueryObject(new Bar) );
396 : }
397 :
398 : {
399 1 : printf("\n### Test 7: can you compare one |nsCOMPtr| with another [!=]?\n");
400 :
401 2 : nsRefPtr<Foo> foo1p( do_QueryObject(new Foo) );
402 :
403 : // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|?
404 : //AnFooPtrPtrContext(&foo1p);
405 :
406 : // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|?
407 : //AVoidPtrPtrContext(&foo1p);
408 :
409 2 : nsRefPtr<Foo> foo2p( do_QueryObject(new Foo) );
410 :
411 1 : if ( foo1p != foo2p )
412 1 : printf("foo1p != foo2p\n");
413 : else
414 0 : printf("foo1p == foo2p\n");
415 :
416 1 : printf("\n### Test 7.5: can you compare a |nsCOMPtr| with NULL, 0, nsnull [!=]?\n");
417 1 : if ( foo1p != 0 )
418 1 : printf("foo1p != 0\n");
419 1 : if ( 0 != foo1p )
420 1 : printf("0 != foo1p\n");
421 1 : if ( foo1p == 0 )
422 0 : printf("foo1p == 0\n");
423 1 : if ( 0 == foo1p )
424 0 : printf("0 == foo1p\n");
425 :
426 :
427 1 : Foo* raw_foo2p = foo2p.get();
428 :
429 1 : printf("\n### Test 8: can you compare a |nsCOMPtr| with a raw interface pointer [!=]?\n");
430 1 : if ( foo1p.get() != raw_foo2p )
431 1 : printf("foo1p != raw_foo2p\n");
432 : else
433 0 : printf("foo1p == raw_foo2p\n");
434 :
435 :
436 1 : printf("\n### Test 9: can you assign one |nsCOMPtr| into another?\n");
437 1 : foo1p = foo2p;
438 :
439 1 : printf("\n### Test 10: can you compare one |nsCOMPtr| with another [==]?\n");
440 1 : if ( foo1p == foo2p )
441 1 : printf("foo1p == foo2p\n");
442 : else
443 0 : printf("foo1p != foo2p\n");
444 :
445 1 : printf("\n### Test 11: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n");
446 1 : if ( raw_foo2p == foo2p.get() )
447 1 : printf("raw_foo2p == foo2p\n");
448 : else
449 0 : printf("raw_foo2p != foo2p\n");
450 :
451 : #if 1
452 1 : printf("\n### Test 11.5: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n");
453 1 : if ( nsRefPtr<Foo>( raw_foo2p ) == foo2p )
454 1 : printf("raw_foo2p == foo2p\n");
455 : else
456 0 : printf("raw_foo2p != foo2p\n");
457 : #endif
458 :
459 1 : printf("\n### Test 12: bare pointer test?\n");
460 1 : if ( foo1p )
461 1 : printf("foo1p is not NULL\n");
462 : else
463 0 : printf("foo1p is NULL\n");
464 :
465 1 : printf("\n### Test 13: numeric pointer test?\n");
466 1 : if ( foo1p == 0 )
467 0 : printf("foo1p is NULL\n");
468 : else
469 1 : printf("foo1p is not NULL\n");
470 :
471 : #if 0
472 : if ( foo1p == 1 )
473 : printf("foo1p allowed compare with in\n");
474 : #endif
475 :
476 1 : printf("\n### Test 14: how about when two |nsCOMPtr|s referring to the same object go out of scope?\n");
477 : }
478 :
479 : {
480 1 : printf("\n### Test 15,16 ...setup...\n");
481 1 : Foo* raw_foo1p = new Foo;
482 1 : raw_foo1p->AddRef();
483 :
484 1 : Foo* raw_foo2p = new Foo;
485 1 : raw_foo2p->AddRef();
486 :
487 1 : printf("\n### Test 15: what if I don't want to |AddRef| when I construct?\n");
488 2 : nsRefPtr<Foo> foo1p( dont_AddRef(raw_foo1p) );
489 : //nsRefPtr<Foo> foo1p = dont_AddRef(raw_foo1p);
490 :
491 1 : printf("\n### Test 16: what if I don't want to |AddRef| when I assign in?\n");
492 2 : nsRefPtr<Foo> foo2p;
493 1 : foo2p = dont_AddRef(raw_foo2p);
494 : }
495 :
496 :
497 :
498 :
499 :
500 :
501 :
502 : {
503 1 : printf("\n### setup for Test 17\n");
504 2 : nsRefPtr<Foo> foop;
505 1 : printf("### Test 17: basic parameter behavior?\n");
506 1 : CreateFoo( nsRefPtrGetterAddRefs<Foo>(foop) );
507 : }
508 1 : printf("### End Test 17\n");
509 :
510 :
511 : {
512 1 : printf("\n### setup for Test 18\n");
513 2 : nsRefPtr<Foo> foop;
514 1 : printf("### Test 18: basic parameter behavior, using the short form?\n");
515 1 : CreateFoo( getter_AddRefs(foop) );
516 : }
517 1 : printf("### End Test 18\n");
518 :
519 :
520 : {
521 1 : printf("\n### setup for Test 19, 20\n");
522 2 : nsRefPtr<Foo> foop;
523 1 : printf("### Test 19: reference parameter behavior?\n");
524 1 : set_a_Foo(address_of(foop));
525 :
526 1 : printf("### Test 20: return value behavior?\n");
527 1 : foop = return_a_Foo();
528 : }
529 1 : printf("### End Test 19, 20\n");
530 :
531 : {
532 1 : printf("\n### setup for Test 21\n");
533 2 : nsRefPtr<Foo> fooP;
534 :
535 1 : printf("### Test 21: is |QueryInterface| called on assigning in a raw pointer?\n");
536 1 : fooP = do_QueryObject(new Foo);
537 : }
538 1 : printf("### End Test 21\n");
539 :
540 : {
541 1 : printf("\n### setup for Test 22\n");
542 2 : nsRefPtr<Foo> fooP;
543 1 : fooP = do_QueryObject(new Foo);
544 :
545 2 : nsRefPtr<Foo> foo2P;
546 :
547 1 : printf("### Test 22: is |QueryInterface| _not_ called when assigning in a smart-pointer of the same type?\n");
548 1 : foo2P = fooP;
549 : }
550 1 : printf("### End Test 22\n");
551 :
552 : {
553 1 : printf("\n### setup for Test 23\n");
554 2 : nsRefPtr<Bar> barP( do_QueryObject(new Bar) );
555 :
556 1 : printf("### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n");
557 :
558 2 : nsRefPtr<Foo> fooP( do_QueryObject(barP) );
559 1 : if ( fooP )
560 1 : printf("an Bar* is an Foo*\n");
561 : }
562 1 : printf("### End Test 23\n");
563 :
564 :
565 : {
566 1 : printf("\n### setup for Test 24\n");
567 2 : nsRefPtr<Foo> fooP( do_QueryObject(new Foo) );
568 :
569 1 : printf("### Test 24: does |forget| avoid an AddRef/Release when assigning to another nsCOMPtr?\n");
570 1 : nsRefPtr<Foo> fooP2( fooP.forget() );
571 : }
572 1 : printf("### End Test 24\n");
573 :
574 : {
575 2 : nsRefPtr<Foo> fooP;
576 :
577 1 : AnFooPtrPtrContext( getter_AddRefs(fooP) );
578 1 : AVoidPtrPtrContext( getter_AddRefs(fooP) );
579 : }
580 :
581 :
582 1 : printf("\n### Test 25: will a static |nsCOMPtr| |Release| before program termination?\n");
583 1 : gFoop = do_QueryObject(new Foo);
584 :
585 1 : printf("<<main()\n");
586 1 : return 0;
587 3 : }
588 :
|