michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include "nsCOMPtr.h" michael@0: #include "nsISupports.h" michael@0: michael@0: #define NS_IFOO_IID \ michael@0: { 0x6f7652e0, 0xee43, 0x11d1, \ michael@0: { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } michael@0: michael@0: class IFoo : public nsISupports michael@0: { michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID) michael@0: michael@0: public: michael@0: IFoo(); michael@0: // virtual dtor because IBar uses our Release() michael@0: virtual ~IFoo(); michael@0: michael@0: NS_IMETHOD_(MozExternalRefCountType) AddRef(); michael@0: NS_IMETHOD_(MozExternalRefCountType) Release(); michael@0: NS_IMETHOD QueryInterface( const nsIID&, void** ); michael@0: michael@0: static void print_totals(); michael@0: michael@0: private: michael@0: unsigned int refcount_; michael@0: michael@0: static unsigned int total_constructions_; michael@0: static unsigned int total_destructions_; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(IFoo, NS_IFOO_IID) michael@0: michael@0: class IBar; michael@0: michael@0: // some types I'll need michael@0: typedef unsigned long NS_RESULT; michael@0: michael@0: // some functions I'll need (and define below) michael@0: nsresult CreateIFoo( void** ); michael@0: nsresult CreateIBar( void** result ); michael@0: void AnIFooPtrPtrContext( IFoo** ); michael@0: void AnISupportsPtrPtrContext( nsISupports** ); michael@0: void AVoidPtrPtrContext( void** ); michael@0: void set_a_IFoo( nsCOMPtr* result ); michael@0: nsCOMPtr return_a_IFoo(); michael@0: michael@0: michael@0: michael@0: michael@0: unsigned int IFoo::total_constructions_; michael@0: unsigned int IFoo::total_destructions_; michael@0: michael@0: class test_message michael@0: { michael@0: public: michael@0: test_message() michael@0: { michael@0: printf("BEGIN unit tests for |nsCOMPtr|, compiled " __DATE__ "\n"); michael@0: } michael@0: michael@0: ~test_message() michael@0: { michael@0: IFoo::print_totals(); michael@0: printf("END unit tests for |nsCOMPtr|.\n"); michael@0: } michael@0: }; michael@0: michael@0: test_message gTestMessage; michael@0: michael@0: michael@0: /* michael@0: ... michael@0: */ michael@0: michael@0: void michael@0: IFoo::print_totals() michael@0: { michael@0: printf("total constructions/destructions --> %d/%d\n", michael@0: total_constructions_, total_destructions_); michael@0: } michael@0: michael@0: IFoo::IFoo() michael@0: : refcount_(0) michael@0: { michael@0: ++total_constructions_; michael@0: printf(" new IFoo@%p [#%d]\n", michael@0: static_cast(this), total_constructions_); michael@0: } michael@0: michael@0: IFoo::~IFoo() michael@0: { michael@0: ++total_destructions_; michael@0: printf("IFoo@%p::~IFoo() [#%d]\n", michael@0: static_cast(this), total_destructions_); michael@0: } michael@0: michael@0: MozExternalRefCountType michael@0: IFoo::AddRef() michael@0: { michael@0: ++refcount_; michael@0: printf("IFoo@%p::AddRef(), refcount --> %d\n", michael@0: static_cast(this), refcount_); michael@0: return refcount_; michael@0: } michael@0: michael@0: MozExternalRefCountType michael@0: IFoo::Release() michael@0: { michael@0: int newcount = --refcount_; michael@0: if ( newcount == 0 ) michael@0: printf(">>"); michael@0: michael@0: printf("IFoo@%p::Release(), refcount --> %d\n", michael@0: static_cast(this), refcount_); michael@0: michael@0: if ( newcount == 0 ) michael@0: { michael@0: printf(" delete IFoo@%p\n", static_cast(this)); michael@0: printf("<(this)); michael@0: delete this; michael@0: } michael@0: michael@0: return newcount; michael@0: } michael@0: michael@0: nsresult michael@0: IFoo::QueryInterface( const nsIID& aIID, void** aResult ) michael@0: { michael@0: printf("IFoo@%p::QueryInterface()\n", static_cast(this)); michael@0: nsISupports* rawPtr = 0; michael@0: nsresult status = NS_OK; michael@0: michael@0: if ( aIID.Equals(NS_GET_IID(IFoo)) ) michael@0: rawPtr = this; michael@0: else michael@0: { michael@0: nsID iid_of_ISupports = NS_ISUPPORTS_IID; michael@0: if ( aIID.Equals(iid_of_ISupports) ) michael@0: rawPtr = static_cast(this); michael@0: else michael@0: status = NS_ERROR_NO_INTERFACE; michael@0: } michael@0: michael@0: NS_IF_ADDREF(rawPtr); michael@0: *aResult = rawPtr; michael@0: michael@0: return status; michael@0: } michael@0: michael@0: nsresult michael@0: CreateIFoo( void** result ) michael@0: // a typical factory function (that calls AddRef) michael@0: { michael@0: printf(">>CreateIFoo() --> "); michael@0: IFoo* foop = new IFoo; michael@0: printf("IFoo@%p\n", static_cast(foop)); michael@0: michael@0: foop->AddRef(); michael@0: *result = foop; michael@0: michael@0: printf("<* result ) michael@0: { michael@0: printf(">>set_a_IFoo()\n"); michael@0: assert(result); michael@0: michael@0: nsCOMPtr foop( do_QueryInterface(new IFoo) ); michael@0: *result = foop; michael@0: printf("< michael@0: return_a_IFoo() michael@0: { michael@0: printf(">>return_a_IFoo()\n"); michael@0: nsCOMPtr foop( do_QueryInterface(new IFoo) ); michael@0: printf("<(this)); michael@0: } michael@0: michael@0: IBar::~IBar() michael@0: { michael@0: printf("IBar@%p::~IBar()\n", static_cast(this)); michael@0: } michael@0: michael@0: nsresult michael@0: IBar::QueryInterface( const nsID& aIID, void** aResult ) michael@0: { michael@0: printf("IBar@%p::QueryInterface()\n", static_cast(this)); michael@0: nsISupports* rawPtr = 0; michael@0: nsresult status = NS_OK; michael@0: michael@0: if ( aIID.Equals(NS_GET_IID(IBar)) ) michael@0: rawPtr = this; michael@0: else if ( aIID.Equals(NS_GET_IID(IFoo)) ) michael@0: rawPtr = static_cast(this); michael@0: else michael@0: { michael@0: nsID iid_of_ISupports = NS_ISUPPORTS_IID; michael@0: if ( aIID.Equals(iid_of_ISupports) ) michael@0: rawPtr = static_cast(this); michael@0: else michael@0: status = NS_ERROR_NO_INTERFACE; michael@0: } michael@0: michael@0: NS_IF_ADDREF(rawPtr); michael@0: *aResult = rawPtr; michael@0: michael@0: return status; michael@0: } michael@0: michael@0: michael@0: michael@0: nsresult michael@0: CreateIBar( void** result ) michael@0: // a typical factory function (that calls AddRef) michael@0: { michael@0: printf(">>CreateIBar() --> "); michael@0: IBar* barp = new IBar; michael@0: printf("IBar@%p\n", static_cast(barp)); michael@0: michael@0: barp->AddRef(); michael@0: *result = barp; michael@0: michael@0: printf("<(&barP)); michael@0: michael@0: if ( barP ) michael@0: { michael@0: IFoo* fooP = 0; michael@0: if ( NS_SUCCEEDED( result = barP->QueryInterface(NS_GET_IID(IFoo), reinterpret_cast(&fooP)) ) ) michael@0: { michael@0: fooP->print_totals(); michael@0: NS_RELEASE(fooP); michael@0: } michael@0: michael@0: NS_RELEASE(barP); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: static michael@0: nsresult michael@0: TestBloat_Smart() michael@0: { michael@0: nsCOMPtr barP; michael@0: nsresult result = CreateIBar( getter_AddRefs(barP) ); michael@0: michael@0: nsCOMPtr fooP( do_QueryInterface(barP, &result) ); michael@0: michael@0: if ( fooP ) michael@0: fooP->print_totals(); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: michael@0: michael@0: nsCOMPtr gFoop; michael@0: michael@0: int michael@0: main() michael@0: { michael@0: printf(">>main()\n"); michael@0: michael@0: printf("sizeof(nsCOMPtr) --> %u\n", unsigned(sizeof(nsCOMPtr))); michael@0: michael@0: TestBloat_Raw_Unsafe(); michael@0: TestBloat_Smart(); michael@0: michael@0: michael@0: { michael@0: printf("\n### Test 1: will a |nsCOMPtr| call |AddRef| on a pointer assigned into it?\n"); michael@0: nsCOMPtr foop( do_QueryInterface(new IFoo) ); michael@0: michael@0: printf("\n### Test 2: will a |nsCOMPtr| |Release| its old pointer when a new one is assigned in?\n"); michael@0: foop = do_QueryInterface(new IFoo); michael@0: michael@0: // [Shouldn't compile] Is it a compile time error to try to |AddRef| by hand? michael@0: //foop->AddRef(); michael@0: michael@0: // [Shouldn't compile] Is it a compile time error to try to |Release| be hand? michael@0: //foop->Release(); michael@0: michael@0: // [Shouldn't compile] Is it a compile time error to try to |delete| an |nsCOMPtr|? michael@0: //delete foop; michael@0: michael@0: printf("\n### Test 3: can you |AddRef| if you must?\n"); michael@0: static_cast(foop)->AddRef(); michael@0: michael@0: printf("\n### Test 4: can you |Release| if you must?\n"); michael@0: static_cast(foop)->Release(); michael@0: michael@0: printf("\n### Test 5: will a |nsCOMPtr| |Release| when it goes out of scope?\n"); michael@0: } michael@0: michael@0: { michael@0: printf("\n### Test 6: will a |nsCOMPtr| call the correct destructor?\n"); michael@0: nsCOMPtr foop( do_QueryInterface(new IBar) ); michael@0: } michael@0: michael@0: { michael@0: printf("\n### Test 7: can you compare one |nsCOMPtr| with another [!=]?\n"); michael@0: michael@0: nsCOMPtr foo1p( do_QueryInterface(new IFoo) ); michael@0: michael@0: // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|? michael@0: //AnIFooPtrPtrContext(&foo1p); michael@0: michael@0: // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|? michael@0: //AVoidPtrPtrContext(&foo1p); michael@0: michael@0: nsCOMPtr foo2p( do_QueryInterface(new IFoo) ); michael@0: michael@0: if ( foo1p != foo2p ) michael@0: printf("foo1p != foo2p\n"); michael@0: else michael@0: printf("foo1p == foo2p\n"); michael@0: michael@0: printf("\n### Test 7.5: can you compare a |nsCOMPtr| with NULL, 0, nullptr [!=]?\n"); michael@0: if ( foo1p != 0 ) michael@0: printf("foo1p != 0\n"); michael@0: if ( 0 != foo1p ) michael@0: printf("0 != foo1p\n"); michael@0: if ( foo1p == 0 ) michael@0: printf("foo1p == 0\n"); michael@0: if ( 0 == foo1p ) michael@0: printf("0 == foo1p\n"); michael@0: michael@0: michael@0: IFoo* raw_foo2p = foo2p.get(); michael@0: michael@0: printf("\n### Test 8: can you compare a |nsCOMPtr| with a raw interface pointer [!=]?\n"); michael@0: if ( foo1p.get() != raw_foo2p ) michael@0: printf("foo1p != raw_foo2p\n"); michael@0: else michael@0: printf("foo1p == raw_foo2p\n"); michael@0: michael@0: michael@0: printf("\n### Test 9: can you assign one |nsCOMPtr| into another?\n"); michael@0: foo1p = foo2p; michael@0: michael@0: printf("\n### Test 10: can you compare one |nsCOMPtr| with another [==]?\n"); michael@0: if ( foo1p == foo2p ) michael@0: printf("foo1p == foo2p\n"); michael@0: else michael@0: printf("foo1p != foo2p\n"); michael@0: michael@0: printf("\n### Test 11: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n"); michael@0: if ( raw_foo2p == foo2p.get() ) michael@0: printf("raw_foo2p == foo2p\n"); michael@0: else michael@0: printf("raw_foo2p != foo2p\n"); michael@0: michael@0: #if 1 michael@0: printf("\n### Test 11.5: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n"); michael@0: if ( nsCOMPtr( raw_foo2p ) == foo2p ) michael@0: printf("raw_foo2p == foo2p\n"); michael@0: else michael@0: printf("raw_foo2p != foo2p\n"); michael@0: #endif michael@0: michael@0: printf("\n### Test 12: bare pointer test?\n"); michael@0: if ( foo1p ) michael@0: printf("foo1p is not NULL\n"); michael@0: else michael@0: printf("foo1p is NULL\n"); michael@0: michael@0: printf("\n### Test 13: numeric pointer test?\n"); michael@0: if ( foo1p == 0 ) michael@0: printf("foo1p is NULL\n"); michael@0: else michael@0: printf("foo1p is not NULL\n"); michael@0: michael@0: #if 0 michael@0: if ( foo1p == 1 ) michael@0: printf("foo1p allowed compare with in\n"); michael@0: #endif michael@0: michael@0: printf("\n### Test 14: how about when two |nsCOMPtr|s referring to the same object go out of scope?\n"); michael@0: } michael@0: michael@0: { michael@0: printf("\n### Test 15,16 ...setup...\n"); michael@0: IFoo* raw_foo1p = new IFoo; michael@0: raw_foo1p->AddRef(); michael@0: michael@0: IFoo* raw_foo2p = new IFoo; michael@0: raw_foo2p->AddRef(); michael@0: michael@0: printf("\n### Test 15: what if I don't want to |AddRef| when I construct?\n"); michael@0: nsCOMPtr foo1p( dont_AddRef(raw_foo1p) ); michael@0: //nsCOMPtr foo1p = dont_AddRef(raw_foo1p); michael@0: michael@0: printf("\n### Test 16: what if I don't want to |AddRef| when I assign in?\n"); michael@0: nsCOMPtr foo2p; michael@0: foo2p = dont_AddRef(raw_foo2p); michael@0: } michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: { michael@0: printf("\n### setup for Test 17\n"); michael@0: nsCOMPtr foop; michael@0: printf("### Test 17: basic parameter behavior?\n"); michael@0: CreateIFoo( nsGetterAddRefs(foop) ); michael@0: } michael@0: printf("### End Test 17\n"); michael@0: michael@0: michael@0: { michael@0: printf("\n### setup for Test 18\n"); michael@0: nsCOMPtr foop; michael@0: printf("### Test 18: basic parameter behavior, using the short form?\n"); michael@0: CreateIFoo( getter_AddRefs(foop) ); michael@0: } michael@0: printf("### End Test 18\n"); michael@0: michael@0: michael@0: { michael@0: printf("\n### setup for Test 19, 20\n"); michael@0: nsCOMPtr foop; michael@0: printf("### Test 19: reference parameter behavior?\n"); michael@0: set_a_IFoo(address_of(foop)); michael@0: michael@0: printf("### Test 20: return value behavior?\n"); michael@0: foop = return_a_IFoo(); michael@0: } michael@0: printf("### End Test 19, 20\n"); michael@0: michael@0: { michael@0: printf("\n### setup for Test 21\n"); michael@0: nsCOMPtr fooP; michael@0: michael@0: printf("### Test 21: is |QueryInterface| called on assigning in a raw pointer?\n"); michael@0: fooP = do_QueryInterface(new IFoo); michael@0: } michael@0: printf("### End Test 21\n"); michael@0: michael@0: { michael@0: printf("\n### setup for Test 22\n"); michael@0: nsCOMPtr fooP; michael@0: fooP = do_QueryInterface(new IFoo); michael@0: michael@0: nsCOMPtr foo2P; michael@0: michael@0: printf("### Test 22: is |QueryInterface| _not_ called when assigning in a smart-pointer of the same type?\n"); michael@0: foo2P = fooP; michael@0: } michael@0: printf("### End Test 22\n"); michael@0: michael@0: { michael@0: printf("\n### setup for Test 23\n"); michael@0: nsCOMPtr barP( do_QueryInterface(new IBar) ); michael@0: michael@0: printf("### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n"); michael@0: michael@0: nsCOMPtr fooP( do_QueryInterface(barP) ); michael@0: if ( fooP ) michael@0: printf("an IBar* is an IFoo*\n"); michael@0: } michael@0: printf("### End Test 23\n"); michael@0: michael@0: michael@0: { michael@0: printf("\n### setup for Test 24\n"); michael@0: nsCOMPtr fooP( do_QueryInterface(new IFoo) ); michael@0: michael@0: printf("### Test 24: does |forget| avoid an AddRef/Release when assigning to another nsCOMPtr?\n"); michael@0: nsCOMPtr fooP2( fooP.forget() ); michael@0: } michael@0: printf("### End Test 24\n"); michael@0: michael@0: { michael@0: nsCOMPtr fooP; michael@0: michael@0: AnIFooPtrPtrContext( getter_AddRefs(fooP) ); michael@0: AVoidPtrPtrContext( getter_AddRefs(fooP) ); michael@0: } michael@0: michael@0: michael@0: { michael@0: nsCOMPtr supportsP; michael@0: michael@0: AVoidPtrPtrContext( getter_AddRefs(supportsP) ); michael@0: AnISupportsPtrPtrContext( getter_AddRefs(supportsP) ); michael@0: } michael@0: michael@0: michael@0: printf("\n### Test 25: will a static |nsCOMPtr| |Release| before program termination?\n"); michael@0: gFoop = do_QueryInterface(new IFoo); michael@0: michael@0: printf("<