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 "nsISupports.h"
43 :
44 : #define NS_IFOO_IID \
45 : { 0x6f7652e0, 0xee43, 0x11d1, \
46 : { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
47 :
48 : class IFoo : public nsISupports
49 : {
50 : public:
51 16 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
52 :
53 : public:
54 : IFoo();
55 : // virtual dtor because IBar uses our Release()
56 : virtual ~IFoo();
57 :
58 : NS_IMETHOD_(nsrefcnt) AddRef();
59 : NS_IMETHOD_(nsrefcnt) Release();
60 : NS_IMETHOD QueryInterface( const nsIID&, void** );
61 :
62 : static void print_totals();
63 :
64 : private:
65 : unsigned int refcount_;
66 :
67 : static unsigned int total_constructions_;
68 : static unsigned int total_destructions_;
69 : };
70 :
71 : NS_DEFINE_STATIC_IID_ACCESSOR(IFoo, NS_IFOO_IID)
72 :
73 : class IBar;
74 :
75 : // some types I'll need
76 : typedef unsigned long NS_RESULT;
77 :
78 : // some functions I'll need (and define below)
79 : nsresult CreateIFoo( void** );
80 : nsresult CreateIBar( void** result );
81 : void AnIFooPtrPtrContext( IFoo** );
82 : void AnISupportsPtrPtrContext( nsISupports** );
83 : void AVoidPtrPtrContext( void** );
84 : void set_a_IFoo( nsCOMPtr<IFoo>* result );
85 : nsCOMPtr<IFoo> return_a_IFoo();
86 :
87 :
88 :
89 :
90 : unsigned int IFoo::total_constructions_;
91 : unsigned int IFoo::total_destructions_;
92 :
93 : class test_message
94 : {
95 : public:
96 1 : test_message()
97 : {
98 1 : printf("BEGIN unit tests for |nsCOMPtr|, compiled " __DATE__ "\n");
99 1 : }
100 :
101 1 : ~test_message()
102 : {
103 1 : IFoo::print_totals();
104 1 : printf("END unit tests for |nsCOMPtr|.\n");
105 1 : }
106 : };
107 :
108 1 : test_message gTestMessage;
109 :
110 :
111 : /*
112 : ...
113 : */
114 :
115 : void
116 3 : IFoo::print_totals()
117 : {
118 : printf("total constructions/destructions --> %d/%d\n",
119 3 : total_constructions_, total_destructions_);
120 3 : }
121 :
122 18 : IFoo::IFoo()
123 18 : : refcount_(0)
124 : {
125 18 : ++total_constructions_;
126 : printf(" new IFoo@%p [#%d]\n",
127 18 : static_cast<void*>(this), total_constructions_);
128 18 : }
129 :
130 32 : IFoo::~IFoo()
131 : {
132 18 : ++total_destructions_;
133 : printf("IFoo@%p::~IFoo() [#%d]\n",
134 18 : static_cast<void*>(this), total_destructions_);
135 64 : }
136 :
137 : nsrefcnt
138 34 : IFoo::AddRef()
139 : {
140 34 : ++refcount_;
141 : printf("IFoo@%p::AddRef(), refcount --> %d\n",
142 34 : static_cast<void*>(this), refcount_);
143 34 : return refcount_;
144 : }
145 :
146 : nsrefcnt
147 34 : IFoo::Release()
148 : {
149 34 : int newcount = --refcount_;
150 34 : if ( newcount == 0 )
151 18 : printf(">>");
152 :
153 : printf("IFoo@%p::Release(), refcount --> %d\n",
154 34 : static_cast<void*>(this), refcount_);
155 :
156 34 : if ( newcount == 0 )
157 : {
158 18 : printf(" delete IFoo@%p\n", static_cast<void*>(this));
159 18 : printf("<<IFoo@%p::Release()\n", static_cast<void*>(this));
160 18 : delete this;
161 : }
162 :
163 34 : return newcount;
164 : }
165 :
166 : nsresult
167 16 : IFoo::QueryInterface( const nsIID& aIID, void** aResult )
168 : {
169 16 : printf("IFoo@%p::QueryInterface()\n", static_cast<void*>(this));
170 16 : nsISupports* rawPtr = 0;
171 16 : nsresult status = NS_OK;
172 :
173 16 : if ( aIID.Equals(GetIID()) )
174 16 : rawPtr = this;
175 : else
176 : {
177 0 : nsID iid_of_ISupports = NS_ISUPPORTS_IID;
178 0 : if ( aIID.Equals(iid_of_ISupports) )
179 0 : rawPtr = static_cast<nsISupports*>(this);
180 : else
181 0 : status = NS_ERROR_NO_INTERFACE;
182 : }
183 :
184 16 : NS_IF_ADDREF(rawPtr);
185 16 : *aResult = rawPtr;
186 :
187 16 : return status;
188 : }
189 :
190 : nsresult
191 2 : CreateIFoo( void** result )
192 : // a typical factory function (that calls AddRef)
193 : {
194 2 : printf(">>CreateIFoo() --> ");
195 2 : IFoo* foop = new IFoo;
196 2 : printf("IFoo@%p\n", static_cast<void*>(foop));
197 :
198 2 : foop->AddRef();
199 2 : *result = foop;
200 :
201 2 : printf("<<CreateIFoo()\n");
202 2 : return 0;
203 : }
204 :
205 : void
206 1 : set_a_IFoo( nsCOMPtr<IFoo>* result )
207 : {
208 1 : printf(">>set_a_IFoo()\n");
209 1 : assert(result);
210 :
211 2 : nsCOMPtr<IFoo> foop( do_QueryInterface(new IFoo) );
212 1 : *result = foop;
213 1 : printf("<<set_a_IFoo()\n");
214 1 : }
215 :
216 : nsCOMPtr<IFoo>
217 1 : return_a_IFoo()
218 : {
219 1 : printf(">>return_a_IFoo()\n");
220 1 : nsCOMPtr<IFoo> foop( do_QueryInterface(new IFoo) );
221 1 : printf("<<return_a_IFoo()\n");
222 : return foop;
223 : }
224 :
225 :
226 :
227 :
228 : #define NS_IBAR_IID \
229 : { 0x6f7652e1, 0xee43, 0x11d1, \
230 : { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
231 :
232 : class IBar : public IFoo
233 : {
234 : public:
235 6 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_IBAR_IID)
236 :
237 : public:
238 : IBar();
239 : virtual ~IBar();
240 :
241 : NS_IMETHOD QueryInterface( const nsIID&, void** );
242 : };
243 :
244 : NS_DEFINE_STATIC_IID_ACCESSOR(IBar, NS_IBAR_IID)
245 :
246 4 : IBar::IBar()
247 : {
248 4 : printf(" new IBar@%p\n", static_cast<void*>(this));
249 4 : }
250 :
251 12 : IBar::~IBar()
252 : {
253 4 : printf("IBar@%p::~IBar()\n", static_cast<void*>(this));
254 16 : }
255 :
256 : nsresult
257 6 : IBar::QueryInterface( const nsID& aIID, void** aResult )
258 : {
259 6 : printf("IBar@%p::QueryInterface()\n", static_cast<void*>(this));
260 6 : nsISupports* rawPtr = 0;
261 6 : nsresult status = NS_OK;
262 :
263 6 : if ( aIID.Equals(GetIID()) )
264 2 : rawPtr = this;
265 4 : else if ( aIID.Equals(NS_GET_IID(IFoo)) )
266 4 : rawPtr = static_cast<IFoo*>(this);
267 : else
268 : {
269 0 : nsID iid_of_ISupports = NS_ISUPPORTS_IID;
270 0 : if ( aIID.Equals(iid_of_ISupports) )
271 0 : rawPtr = static_cast<nsISupports*>(this);
272 : else
273 0 : status = NS_ERROR_NO_INTERFACE;
274 : }
275 :
276 6 : NS_IF_ADDREF(rawPtr);
277 6 : *aResult = rawPtr;
278 :
279 6 : return status;
280 : }
281 :
282 :
283 :
284 : nsresult
285 2 : CreateIBar( void** result )
286 : // a typical factory function (that calls AddRef)
287 : {
288 2 : printf(">>CreateIBar() --> ");
289 2 : IBar* barp = new IBar;
290 2 : printf("IBar@%p\n", static_cast<void*>(barp));
291 :
292 2 : barp->AddRef();
293 2 : *result = barp;
294 :
295 2 : printf("<<CreateIBar()\n");
296 2 : return 0;
297 : }
298 :
299 : void
300 1 : AnIFooPtrPtrContext( IFoo** )
301 : {
302 1 : }
303 :
304 : void
305 2 : AVoidPtrPtrContext( void** )
306 : {
307 2 : }
308 :
309 : void
310 2 : AnISupportsPtrPtrContext( nsISupports** )
311 : {
312 2 : }
313 :
314 : static
315 : nsresult
316 1 : TestBloat_Raw_Unsafe()
317 : {
318 1 : IBar* barP = 0;
319 1 : nsresult result = CreateIBar(reinterpret_cast<void**>(&barP));
320 :
321 1 : if ( barP )
322 : {
323 1 : IFoo* fooP = 0;
324 1 : if ( NS_SUCCEEDED( result = barP->QueryInterface(NS_GET_IID(IFoo), 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 : nsCOMPtr<IBar> barP;
342 1 : nsresult result = CreateIBar( getter_AddRefs(barP) );
343 :
344 2 : nsCOMPtr<IFoo> fooP( do_QueryInterface(barP, &result) );
345 :
346 1 : if ( fooP )
347 1 : fooP->print_totals();
348 :
349 1 : return result;
350 : }
351 :
352 :
353 :
354 :
355 1 : nsCOMPtr<IFoo> gFoop;
356 :
357 : int
358 1 : main()
359 : {
360 1 : printf(">>main()\n");
361 :
362 1 : printf("sizeof(nsCOMPtr<IFoo>) --> %u\n", unsigned(sizeof(nsCOMPtr<IFoo>)));
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 : nsCOMPtr<IFoo> foop( do_QueryInterface(new IFoo) );
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_QueryInterface(new IFoo);
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<IFoo*>(foop)->AddRef();
386 :
387 1 : printf("\n### Test 4: can you |Release| if you must?\n");
388 1 : static_cast<IFoo*>(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 : nsCOMPtr<IFoo> foop( do_QueryInterface(new IBar) );
396 : }
397 :
398 : {
399 1 : printf("\n### Test 7: can you compare one |nsCOMPtr| with another [!=]?\n");
400 :
401 2 : nsCOMPtr<IFoo> foo1p( do_QueryInterface(new IFoo) );
402 :
403 : // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|?
404 : //AnIFooPtrPtrContext(&foo1p);
405 :
406 : // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|?
407 : //AVoidPtrPtrContext(&foo1p);
408 :
409 2 : nsCOMPtr<IFoo> foo2p( do_QueryInterface(new IFoo) );
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 : IFoo* 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 ( nsCOMPtr<IFoo>( 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 : IFoo* raw_foo1p = new IFoo;
482 1 : raw_foo1p->AddRef();
483 :
484 1 : IFoo* raw_foo2p = new IFoo;
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 : nsCOMPtr<IFoo> foo1p( dont_AddRef(raw_foo1p) );
489 : //nsCOMPtr<IFoo> 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 : nsCOMPtr<IFoo> 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 : nsCOMPtr<IFoo> foop;
505 1 : printf("### Test 17: basic parameter behavior?\n");
506 1 : CreateIFoo( nsGetterAddRefs<IFoo>(foop) );
507 : }
508 1 : printf("### End Test 17\n");
509 :
510 :
511 : {
512 1 : printf("\n### setup for Test 18\n");
513 2 : nsCOMPtr<IFoo> foop;
514 1 : printf("### Test 18: basic parameter behavior, using the short form?\n");
515 1 : CreateIFoo( 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 : nsCOMPtr<IFoo> foop;
523 1 : printf("### Test 19: reference parameter behavior?\n");
524 1 : set_a_IFoo(address_of(foop));
525 :
526 1 : printf("### Test 20: return value behavior?\n");
527 1 : foop = return_a_IFoo();
528 : }
529 1 : printf("### End Test 19, 20\n");
530 :
531 : {
532 1 : printf("\n### setup for Test 21\n");
533 2 : nsCOMPtr<IFoo> fooP;
534 :
535 1 : printf("### Test 21: is |QueryInterface| called on assigning in a raw pointer?\n");
536 1 : fooP = do_QueryInterface(new IFoo);
537 : }
538 1 : printf("### End Test 21\n");
539 :
540 : {
541 1 : printf("\n### setup for Test 22\n");
542 2 : nsCOMPtr<IFoo> fooP;
543 1 : fooP = do_QueryInterface(new IFoo);
544 :
545 2 : nsCOMPtr<IFoo> 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 : nsCOMPtr<IBar> barP( do_QueryInterface(new IBar) );
555 :
556 1 : printf("### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n");
557 :
558 2 : nsCOMPtr<IFoo> fooP( do_QueryInterface(barP) );
559 1 : if ( fooP )
560 1 : printf("an IBar* is an IFoo*\n");
561 : }
562 1 : printf("### End Test 23\n");
563 :
564 :
565 : {
566 1 : printf("\n### setup for Test 24\n");
567 2 : nsCOMPtr<IFoo> fooP( do_QueryInterface(new IFoo) );
568 :
569 1 : printf("### Test 24: does |forget| avoid an AddRef/Release when assigning to another nsCOMPtr?\n");
570 1 : nsCOMPtr<IFoo> fooP2( fooP.forget() );
571 : }
572 1 : printf("### End Test 24\n");
573 :
574 : {
575 2 : nsCOMPtr<IFoo> fooP;
576 :
577 1 : AnIFooPtrPtrContext( getter_AddRefs(fooP) );
578 1 : AVoidPtrPtrContext( getter_AddRefs(fooP) );
579 1 : AnISupportsPtrPtrContext( getter_AddRefs(fooP) );
580 : }
581 :
582 :
583 : {
584 2 : nsCOMPtr<nsISupports> supportsP;
585 :
586 1 : AVoidPtrPtrContext( getter_AddRefs(supportsP) );
587 1 : AnISupportsPtrPtrContext( getter_AddRefs(supportsP) );
588 : }
589 :
590 :
591 1 : printf("\n### Test 25: will a static |nsCOMPtr| |Release| before program termination?\n");
592 1 : gFoop = do_QueryInterface(new IFoo);
593 :
594 1 : printf("<<main()\n");
595 1 : return 0;
596 3 : }
597 :
|