Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/tests/gtest/TestCOMPtr.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsCOMPtr.h"
7
#include "gtest/gtest.h"
8
9
#include "mozilla/Unused.h"
10
11
#define NS_IFOO_IID \
12
{ 0x6f7652e0,  0xee43, 0x11d1, \
13
  { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
14
15
namespace TestCOMPtr
16
{
17
18
class IFoo : public nsISupports
19
{
20
public:
21
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
22
23
public:
24
  IFoo();
25
  // virtual dtor because IBar uses our Release()
26
  virtual ~IFoo();
27
28
  NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
29
  NS_IMETHOD_(MozExternalRefCountType) Release() override;
30
  NS_IMETHOD QueryInterface( const nsIID&, void** ) override;
31
32
  unsigned int refcount_;
33
34
  static int total_constructions_;
35
  static int total_destructions_;
36
  static int total_queries_;
37
};
38
39
NS_DEFINE_STATIC_IID_ACCESSOR(IFoo, NS_IFOO_IID)
40
41
int IFoo::total_constructions_;
42
int IFoo::total_destructions_;
43
int IFoo::total_queries_;
44
45
IFoo::IFoo()
46
  : refcount_(0)
47
0
{
48
0
  ++total_constructions_;
49
0
}
50
51
IFoo::~IFoo()
52
0
{
53
0
  ++total_destructions_;
54
0
}
55
56
MozExternalRefCountType
57
IFoo::AddRef()
58
0
{
59
0
  ++refcount_;
60
0
  return refcount_;
61
0
}
62
63
MozExternalRefCountType
64
IFoo::Release()
65
0
{
66
0
  int newcount = --refcount_;
67
0
68
0
  if ( newcount == 0 )
69
0
  {
70
0
    delete this;
71
0
  }
72
0
73
0
  return newcount;
74
0
}
75
76
nsresult
77
IFoo::QueryInterface( const nsIID& aIID, void** aResult )
78
0
{
79
0
  total_queries_++;
80
0
81
0
  nsISupports* rawPtr = 0;
82
0
  nsresult status = NS_OK;
83
0
84
0
  if ( aIID.Equals(NS_GET_IID(IFoo)) )
85
0
    rawPtr = this;
86
0
  else
87
0
  {
88
0
    nsID iid_of_ISupports = NS_ISUPPORTS_IID;
89
0
    if ( aIID.Equals(iid_of_ISupports) )
90
0
      rawPtr = static_cast<nsISupports*>(this);
91
0
    else
92
0
      status = NS_ERROR_NO_INTERFACE;
93
0
  }
94
0
95
0
  NS_IF_ADDREF(rawPtr);
96
0
  *aResult = rawPtr;
97
0
98
0
  return status;
99
0
}
100
101
nsresult
102
CreateIFoo( void** result )
103
// a typical factory function (that calls AddRef)
104
0
{
105
0
  auto* foop = new IFoo;
106
0
107
0
  foop->AddRef();
108
0
  *result = foop;
109
0
110
0
  return NS_OK;
111
0
}
112
113
void
114
set_a_IFoo( nsCOMPtr<IFoo>* result )
115
0
{
116
0
  nsCOMPtr<IFoo> foop( do_QueryInterface(new IFoo) );
117
0
  *result = foop;
118
0
}
119
120
nsCOMPtr<IFoo>
121
return_a_IFoo()
122
0
{
123
0
  nsCOMPtr<IFoo> foop( do_QueryInterface(new IFoo) );
124
0
  return foop;
125
0
}
126
127
#define NS_IBAR_IID \
128
{ 0x6f7652e1,  0xee43, 0x11d1, \
129
  { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
130
131
class IBar : public IFoo
132
{
133
public:
134
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IBAR_IID)
135
136
public:
137
  IBar();
138
  ~IBar() override;
139
140
  NS_IMETHOD QueryInterface( const nsIID&, void** ) override;
141
142
  static int total_destructions_;
143
  static int total_queries_;
144
};
145
146
NS_DEFINE_STATIC_IID_ACCESSOR(IBar, NS_IBAR_IID)
147
148
int IBar::total_destructions_;
149
int IBar::total_queries_;
150
151
IBar::IBar()
152
0
{
153
0
}
154
155
IBar::~IBar()
156
0
{
157
0
  total_destructions_++;
158
0
}
159
160
nsresult
161
IBar::QueryInterface( const nsID& aIID, void** aResult )
162
0
{
163
0
  total_queries_++;
164
0
165
0
  nsISupports* rawPtr = 0;
166
0
  nsresult status = NS_OK;
167
0
168
0
  if ( aIID.Equals(NS_GET_IID(IBar)) )
169
0
    rawPtr = this;
170
0
  else if ( aIID.Equals(NS_GET_IID(IFoo)) )
171
0
    rawPtr = static_cast<IFoo*>(this);
172
0
  else
173
0
  {
174
0
    nsID iid_of_ISupports = NS_ISUPPORTS_IID;
175
0
    if ( aIID.Equals(iid_of_ISupports) )
176
0
      rawPtr = static_cast<nsISupports*>(this);
177
0
    else
178
0
      status = NS_ERROR_NO_INTERFACE;
179
0
  }
180
0
181
0
  NS_IF_ADDREF(rawPtr);
182
0
  *aResult = rawPtr;
183
0
184
0
  return status;
185
0
}
186
187
188
189
nsresult
190
CreateIBar( void** result )
191
  // a typical factory function (that calls AddRef)
192
0
{
193
0
  auto* barp = new IBar;
194
0
195
0
  barp->AddRef();
196
0
  *result = barp;
197
0
198
0
  return NS_OK;
199
0
}
200
201
void
202
AnIFooPtrPtrContext( IFoo** )
203
0
{
204
0
}
205
206
void
207
AVoidPtrPtrContext( void** )
208
0
{
209
0
}
210
211
void
212
AnISupportsPtrPtrContext( nsISupports** )
213
0
{
214
0
}
215
216
} // namespace TestCOMPtr
217
218
using namespace TestCOMPtr;
219
220
TEST(COMPtr, Bloat_Raw_Unsafe)
221
0
{
222
0
  // ER: I'm not sure what this is testing...
223
0
  IBar* barP = 0;
224
0
  nsresult rv = CreateIBar(reinterpret_cast<void**>(&barP));
225
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
226
0
  ASSERT_TRUE(barP);
227
0
228
0
  IFoo* fooP = 0;
229
0
  rv = barP->QueryInterface(NS_GET_IID(IFoo), reinterpret_cast<void**>(&fooP));
230
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
231
0
  ASSERT_TRUE(fooP);
232
0
233
0
  NS_RELEASE(fooP);
234
0
  NS_RELEASE(barP);
235
0
}
236
237
TEST(COMPtr, Bloat_Smart)
238
0
{
239
0
  // ER: I'm not sure what this is testing...
240
0
  nsCOMPtr<IBar> barP;
241
0
  nsresult rv = CreateIBar( getter_AddRefs(barP) );
242
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
243
0
  ASSERT_TRUE(barP);
244
0
245
0
  nsCOMPtr<IFoo> fooP( do_QueryInterface(barP, &rv) );
246
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
247
0
  ASSERT_TRUE(fooP);
248
0
}
249
250
TEST(COMPtr, AddRefAndRelease)
251
0
{
252
0
  IFoo::total_constructions_ = 0;
253
0
  IFoo::total_destructions_ = 0;
254
0
  IBar::total_destructions_ = 0;
255
0
256
0
  {
257
0
    nsCOMPtr<IFoo> foop( do_QueryInterface(new IFoo) );
258
0
    ASSERT_EQ(foop->refcount_, (unsigned int)1);
259
0
    ASSERT_EQ(IFoo::total_constructions_, 1);
260
0
    ASSERT_EQ(IFoo::total_destructions_, 0);
261
0
262
0
    foop = do_QueryInterface(new IFoo);
263
0
    ASSERT_EQ(foop->refcount_, (unsigned int)1);
264
0
    ASSERT_EQ(IFoo::total_constructions_, 2);
265
0
    ASSERT_EQ(IFoo::total_destructions_, 1);
266
0
267
0
    // [Shouldn't compile] Is it a compile time error to try to |AddRef| by hand?
268
0
    //foop->AddRef();
269
0
270
0
    // [Shouldn't compile] Is it a compile time error to try to |Release| be hand?
271
0
    //foop->Release();
272
0
273
0
    // [Shouldn't compile] Is it a compile time error to try to |delete| an |nsCOMPtr|?
274
0
    //delete foop;
275
0
276
0
    static_cast<IFoo*>(foop)->AddRef();
277
0
    ASSERT_EQ(foop->refcount_, (unsigned int)2);
278
0
    ASSERT_EQ(IFoo::total_constructions_, 2);
279
0
    ASSERT_EQ(IFoo::total_destructions_, 1);
280
0
281
0
    static_cast<IFoo*>(foop)->Release();
282
0
    ASSERT_EQ(foop->refcount_, (unsigned int)1);
283
0
    ASSERT_EQ(IFoo::total_constructions_, 2);
284
0
    ASSERT_EQ(IFoo::total_destructions_, 1);
285
0
  }
286
0
287
0
  ASSERT_EQ(IFoo::total_constructions_, 2);
288
0
  ASSERT_EQ(IFoo::total_destructions_, 2);
289
0
290
0
  {
291
0
    nsCOMPtr<IFoo> foop( do_QueryInterface(new IBar) );
292
0
    mozilla::Unused << foop;
293
0
  }
294
0
295
0
  ASSERT_EQ(IBar::total_destructions_, 1);
296
0
}
297
298
void Comparison()
299
0
{
300
0
  IFoo::total_constructions_ = 0;
301
0
  IFoo::total_destructions_ = 0;
302
0
303
0
  {
304
0
    nsCOMPtr<IFoo> foo1p( do_QueryInterface(new IFoo) );
305
0
    nsCOMPtr<IFoo> foo2p( do_QueryInterface(new IFoo) );
306
0
307
0
    ASSERT_EQ(IFoo::total_constructions_, 2);
308
0
309
0
    // Test != operator
310
0
    ASSERT_NE(foo1p, foo2p);
311
0
    ASSERT_NE(foo1p, foo2p.get());
312
0
313
0
    // Test == operator
314
0
    foo1p = foo2p;
315
0
316
0
    ASSERT_EQ(IFoo::total_destructions_, 1);
317
0
318
0
    ASSERT_EQ(foo1p, foo2p);
319
0
    ASSERT_EQ(foo2p, foo2p.get());
320
0
    ASSERT_EQ(foo2p.get(), foo2p);
321
0
322
0
    // Test () operator
323
0
    ASSERT_TRUE(foo1p);
324
0
325
0
    ASSERT_EQ(foo1p->refcount_, (unsigned int)2);
326
0
    ASSERT_EQ(foo2p->refcount_, (unsigned int)2);
327
0
  }
328
0
329
0
  ASSERT_EQ(IFoo::total_destructions_, 2);
330
0
}
331
332
void DontAddRef()
333
0
{
334
0
  {
335
0
    auto* raw_foo1p = new IFoo;
336
0
    raw_foo1p->AddRef();
337
0
338
0
    auto* raw_foo2p = new IFoo;
339
0
    raw_foo2p->AddRef();
340
0
341
0
    nsCOMPtr<IFoo> foo1p( dont_AddRef(raw_foo1p) );
342
0
    ASSERT_EQ(raw_foo1p, foo1p);
343
0
    ASSERT_EQ(foo1p->refcount_, (unsigned int)1);
344
0
345
0
    nsCOMPtr<IFoo> foo2p;
346
0
    foo2p = dont_AddRef(raw_foo2p);
347
0
    ASSERT_EQ(raw_foo2p, foo2p);
348
0
    ASSERT_EQ(foo2p->refcount_, (unsigned int)1);
349
0
  }
350
0
}
351
352
TEST(COMPtr, AssignmentHelpers)
353
0
{
354
0
  IFoo::total_constructions_ = 0;
355
0
  IFoo::total_destructions_ = 0;
356
0
357
0
  {
358
0
    nsCOMPtr<IFoo> foop;
359
0
    ASSERT_FALSE(foop);
360
0
    CreateIFoo( nsGetterAddRefs<IFoo>(foop) );
361
0
    ASSERT_TRUE(foop);
362
0
  }
363
0
364
0
  ASSERT_EQ(IFoo::total_constructions_, 1);
365
0
  ASSERT_EQ(IFoo::total_destructions_, 1);
366
0
367
0
  {
368
0
    nsCOMPtr<IFoo> foop;
369
0
    ASSERT_FALSE(foop);
370
0
    CreateIFoo( getter_AddRefs(foop) );
371
0
    ASSERT_TRUE(foop);
372
0
  }
373
0
374
0
  ASSERT_EQ(IFoo::total_constructions_, 2);
375
0
  ASSERT_EQ(IFoo::total_destructions_, 2);
376
0
377
0
  {
378
0
    nsCOMPtr<IFoo> foop;
379
0
    ASSERT_FALSE(foop);
380
0
    set_a_IFoo(address_of(foop));
381
0
    ASSERT_TRUE(foop);
382
0
383
0
    ASSERT_EQ(IFoo::total_constructions_, 3);
384
0
    ASSERT_EQ(IFoo::total_destructions_, 2);
385
0
386
0
    foop = return_a_IFoo();
387
0
    ASSERT_TRUE(foop);
388
0
389
0
    ASSERT_EQ(IFoo::total_constructions_, 4);
390
0
    ASSERT_EQ(IFoo::total_destructions_, 3);
391
0
  }
392
0
393
0
  ASSERT_EQ(IFoo::total_constructions_, 4);
394
0
  ASSERT_EQ(IFoo::total_destructions_, 4);
395
0
396
0
  {
397
0
    nsCOMPtr<IFoo> fooP( do_QueryInterface(new IFoo) );
398
0
    ASSERT_TRUE(fooP);
399
0
400
0
    ASSERT_EQ(IFoo::total_constructions_, 5);
401
0
    ASSERT_EQ(IFoo::total_destructions_, 4);
402
0
403
0
    nsCOMPtr<IFoo> fooP2( fooP.forget() );
404
0
    ASSERT_TRUE(fooP2);
405
0
406
0
    ASSERT_EQ(IFoo::total_constructions_, 5);
407
0
    ASSERT_EQ(IFoo::total_destructions_, 4);
408
0
  }
409
0
410
0
  ASSERT_EQ(IFoo::total_constructions_, 5);
411
0
  ASSERT_EQ(IFoo::total_destructions_, 5);
412
0
}
413
414
TEST(COMPtr, QueryInterface)
415
0
{
416
0
  IFoo::total_queries_ = 0;
417
0
  IBar::total_queries_ = 0;
418
0
419
0
  {
420
0
    nsCOMPtr<IFoo> fooP;
421
0
    ASSERT_FALSE(fooP);
422
0
    fooP = do_QueryInterface(new IFoo);
423
0
    ASSERT_TRUE(fooP);
424
0
    ASSERT_EQ(IFoo::total_queries_, 1);
425
0
426
0
    nsCOMPtr<IFoo> foo2P;
427
0
428
0
    // Test that |QueryInterface| _not_ called when assigning a smart-pointer
429
0
    // of the same type.);
430
0
    foo2P = fooP;
431
0
    ASSERT_EQ(IFoo::total_queries_, 1);
432
0
  }
433
0
434
0
  {
435
0
    nsCOMPtr<IBar> barP( do_QueryInterface(new IBar) );
436
0
    ASSERT_EQ(IBar::total_queries_, 1);
437
0
438
0
    // Test that |QueryInterface| is called when assigning a smart-pointer of
439
0
    // a different type.
440
0
    nsCOMPtr<IFoo> fooP( do_QueryInterface(barP) );
441
0
    ASSERT_EQ(IBar::total_queries_, 2);
442
0
    ASSERT_EQ(IFoo::total_queries_, 1);
443
0
    ASSERT_TRUE(fooP);
444
0
  }
445
0
}
446
447
TEST(COMPtr, GetterConversions)
448
0
{
449
0
  // This is just a compilation test. We add a few asserts to keep gtest happy.
450
0
  {
451
0
    nsCOMPtr<IFoo> fooP;
452
0
    ASSERT_FALSE(fooP);
453
0
454
0
    AnIFooPtrPtrContext( getter_AddRefs(fooP) );
455
0
    AVoidPtrPtrContext( getter_AddRefs(fooP) );
456
0
  }
457
0
458
0
459
0
  {
460
0
    nsCOMPtr<nsISupports> supportsP;
461
0
    ASSERT_FALSE(supportsP);
462
0
463
0
    AVoidPtrPtrContext( getter_AddRefs(supportsP) );
464
0
    AnISupportsPtrPtrContext( getter_AddRefs(supportsP) );
465
0
  }
466
0
}