|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 // vim:cindent:ts=4:et:sw=4: |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "TestHarness.h" |
|
8 #include "nsCOMArray.h" |
|
9 #include "mozilla/Attributes.h" |
|
10 |
|
11 // {9e70a320-be02-11d1-8031-006008159b5a} |
|
12 #define NS_IFOO_IID \ |
|
13 {0x9e70a320, 0xbe02, 0x11d1, \ |
|
14 {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} |
|
15 |
|
16 class IFoo : public nsISupports { |
|
17 public: |
|
18 |
|
19 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID) |
|
20 |
|
21 NS_IMETHOD_(MozExternalRefCountType) RefCnt() = 0; |
|
22 NS_IMETHOD_(int32_t) ID() = 0; |
|
23 }; |
|
24 |
|
25 NS_DEFINE_STATIC_IID_ACCESSOR(IFoo, NS_IFOO_IID) |
|
26 |
|
27 class Foo MOZ_FINAL : public IFoo { |
|
28 public: |
|
29 |
|
30 Foo(int32_t aID); |
|
31 ~Foo(); |
|
32 |
|
33 // nsISupports implementation |
|
34 NS_DECL_ISUPPORTS |
|
35 |
|
36 // IFoo implementation |
|
37 NS_IMETHOD_(MozExternalRefCountType) RefCnt() { return mRefCnt; } |
|
38 NS_IMETHOD_(int32_t) ID() { return mID; } |
|
39 |
|
40 static int32_t gCount; |
|
41 |
|
42 int32_t mID; |
|
43 }; |
|
44 |
|
45 int32_t Foo::gCount = 0; |
|
46 |
|
47 Foo::Foo(int32_t aID) |
|
48 { |
|
49 mID = aID; |
|
50 ++gCount; |
|
51 } |
|
52 |
|
53 Foo::~Foo() |
|
54 { |
|
55 --gCount; |
|
56 } |
|
57 |
|
58 NS_IMPL_ISUPPORTS(Foo, IFoo) |
|
59 |
|
60 |
|
61 typedef nsCOMArray<IFoo> Array; |
|
62 |
|
63 |
|
64 // {0e70a320-be02-11d1-8031-006008159b5a} |
|
65 #define NS_IBAR_IID \ |
|
66 {0x0e70a320, 0xbe02, 0x11d1, \ |
|
67 {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} |
|
68 |
|
69 class IBar : public nsISupports { |
|
70 public: |
|
71 |
|
72 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IBAR_IID) |
|
73 }; |
|
74 |
|
75 NS_DEFINE_STATIC_IID_ACCESSOR(IBar, NS_IBAR_IID) |
|
76 |
|
77 class Bar MOZ_FINAL : public IBar { |
|
78 public: |
|
79 |
|
80 explicit Bar(nsCOMArray<IBar>& aArray); |
|
81 ~Bar(); |
|
82 |
|
83 // nsISupports implementation |
|
84 NS_DECL_ISUPPORTS |
|
85 |
|
86 static int32_t sReleaseCalled; |
|
87 |
|
88 private: |
|
89 nsCOMArray<IBar>& mArray; |
|
90 }; |
|
91 |
|
92 int32_t Bar::sReleaseCalled = 0; |
|
93 |
|
94 typedef nsCOMArray<IBar> Array2; |
|
95 |
|
96 Bar::Bar(Array2& aArray) |
|
97 : mArray(aArray) |
|
98 { |
|
99 } |
|
100 |
|
101 Bar::~Bar() |
|
102 { |
|
103 if (mArray.RemoveObject(this)) { |
|
104 fail("We should never manage to remove the object here"); |
|
105 } |
|
106 } |
|
107 |
|
108 NS_IMPL_ADDREF(Bar) |
|
109 NS_IMPL_QUERY_INTERFACE(Bar, IBar) |
|
110 |
|
111 NS_IMETHODIMP_(MozExternalRefCountType) |
|
112 Bar::Release(void) |
|
113 { |
|
114 ++Bar::sReleaseCalled; |
|
115 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); |
|
116 NS_ASSERT_OWNINGTHREAD(_class); |
|
117 --mRefCnt; |
|
118 NS_LOG_RELEASE(this, mRefCnt, "Bar"); |
|
119 if (mRefCnt == 0) { |
|
120 mRefCnt = 1; /* stabilize */ |
|
121 delete this; |
|
122 return 0; |
|
123 } |
|
124 return mRefCnt; |
|
125 } |
|
126 |
|
127 |
|
128 int main(int argc, char **argv) |
|
129 { |
|
130 ScopedXPCOM xpcom("nsCOMArrayTests"); |
|
131 if (xpcom.failed()) { |
|
132 return 1; |
|
133 } |
|
134 |
|
135 int rv = 0; |
|
136 |
|
137 Array arr; |
|
138 |
|
139 for (int32_t i = 0; i < 20; ++i) { |
|
140 nsCOMPtr<IFoo> foo = new Foo(i); |
|
141 arr.AppendObject(foo); |
|
142 } |
|
143 |
|
144 if (arr.Count() != 20 || Foo::gCount != 20) { |
|
145 fail("nsCOMArray::AppendObject failed"); |
|
146 rv = 1; |
|
147 } |
|
148 |
|
149 arr.TruncateLength(10); |
|
150 |
|
151 if (arr.Count() != 10 || Foo::gCount != 10) { |
|
152 fail("nsCOMArray::TruncateLength shortening of array failed"); |
|
153 rv = 1; |
|
154 } |
|
155 |
|
156 arr.SetCount(30); |
|
157 |
|
158 if (arr.Count() != 30 || Foo::gCount != 10) { |
|
159 fail("nsCOMArray::SetCount lengthening of array failed"); |
|
160 rv = 1; |
|
161 } |
|
162 |
|
163 for (int32_t i = 0; i < 10; ++i) { |
|
164 if (arr[i] == nullptr) { |
|
165 fail("nsCOMArray elements should be non-null"); |
|
166 rv = 1; |
|
167 break; |
|
168 } |
|
169 } |
|
170 |
|
171 for (int32_t i = 10; i < 30; ++i) { |
|
172 if (arr[i] != nullptr) { |
|
173 fail("nsCOMArray elements should be null"); |
|
174 rv = 1; |
|
175 break; |
|
176 } |
|
177 } |
|
178 |
|
179 int32_t base; |
|
180 { |
|
181 Array2 arr2; |
|
182 |
|
183 IBar *thirdObject = nullptr, |
|
184 *fourthObject = nullptr, |
|
185 *fifthObject = nullptr, |
|
186 *ninthObject = nullptr; |
|
187 for (int32_t i = 0; i < 20; ++i) { |
|
188 nsCOMPtr<IBar> bar = new Bar(arr2); |
|
189 switch (i) { |
|
190 case 2: |
|
191 thirdObject = bar; break; |
|
192 case 3: |
|
193 fourthObject = bar; break; |
|
194 case 4: |
|
195 fifthObject = bar; break; |
|
196 case 8: |
|
197 ninthObject = bar; break; |
|
198 } |
|
199 arr2.AppendObject(bar); |
|
200 } |
|
201 |
|
202 base = Bar::sReleaseCalled; |
|
203 |
|
204 arr2.SetCount(10); |
|
205 if (Bar::sReleaseCalled != base + 10) { |
|
206 fail("Release called multiple times for SetCount"); |
|
207 } |
|
208 if (arr2.Count() != 10) { |
|
209 fail("SetCount(10) should remove exactly ten objects"); |
|
210 } |
|
211 |
|
212 arr2.RemoveObjectAt(9); |
|
213 if (Bar::sReleaseCalled != base + 11) { |
|
214 fail("Release called multiple times for RemoveObjectAt"); |
|
215 } |
|
216 if (arr2.Count() != 9) { |
|
217 fail("RemoveObjectAt should remove exactly one object"); |
|
218 } |
|
219 |
|
220 arr2.RemoveObject(ninthObject); |
|
221 if (Bar::sReleaseCalled != base + 12) { |
|
222 fail("Release called multiple times for RemoveObject"); |
|
223 } |
|
224 if (arr2.Count() != 8) { |
|
225 fail("RemoveObject should remove exactly one object"); |
|
226 } |
|
227 |
|
228 arr2.RemoveObjectsAt(2, 3); |
|
229 if (Bar::sReleaseCalled != base + 15) { |
|
230 fail("Release called more or less than three times for RemoveObjectsAt"); |
|
231 } |
|
232 if (arr2.Count() != 5) { |
|
233 fail("RemoveObjectsAt should remove exactly three objects"); |
|
234 } |
|
235 for (int32_t j = 0; j < arr2.Count(); ++j) { |
|
236 if (arr2.ObjectAt(j) == thirdObject) { |
|
237 fail("RemoveObjectsAt should have removed thirdObject"); |
|
238 } |
|
239 if (arr2.ObjectAt(j) == fourthObject) { |
|
240 fail("RemoveObjectsAt should have removed fourthObject"); |
|
241 } |
|
242 if (arr2.ObjectAt(j) == fifthObject) { |
|
243 fail("RemoveObjectsAt should have removed fifthObject"); |
|
244 } |
|
245 } |
|
246 |
|
247 arr2.RemoveObjectsAt(4, 1); |
|
248 if (Bar::sReleaseCalled != base + 16) { |
|
249 fail("Release called more or less than one time for RemoveObjectsAt"); |
|
250 } |
|
251 if (arr2.Count() != 4) { |
|
252 fail("RemoveObjectsAt should work for removing the last element"); |
|
253 } |
|
254 |
|
255 arr2.Clear(); |
|
256 if (Bar::sReleaseCalled != base + 20) { |
|
257 fail("Release called multiple times for Clear"); |
|
258 } |
|
259 } |
|
260 |
|
261 { |
|
262 Array2 arr2; |
|
263 |
|
264 IBar *thirdElement = nullptr, |
|
265 *fourthElement = nullptr, |
|
266 *fifthElement = nullptr, |
|
267 *ninthElement = nullptr; |
|
268 for (int32_t i = 0; i < 20; ++i) { |
|
269 nsCOMPtr<IBar> bar = new Bar(arr2); |
|
270 switch (i) { |
|
271 case 2: |
|
272 thirdElement = bar; break; |
|
273 case 3: |
|
274 fourthElement = bar; break; |
|
275 case 4: |
|
276 fifthElement = bar; break; |
|
277 case 8: |
|
278 ninthElement = bar; break; |
|
279 } |
|
280 arr2.AppendElement(bar); |
|
281 } |
|
282 |
|
283 base = Bar::sReleaseCalled; |
|
284 |
|
285 arr2.TruncateLength(10); |
|
286 if (Bar::sReleaseCalled != base + 10) { |
|
287 fail("Release called multiple times for TruncateLength"); |
|
288 } |
|
289 if (arr2.Length() != 10) { |
|
290 fail("TruncateLength(10) should remove exactly ten objects"); |
|
291 } |
|
292 |
|
293 arr2.RemoveElementAt(9); |
|
294 if (Bar::sReleaseCalled != base + 11) { |
|
295 fail("Release called multiple times for RemoveElementAt"); |
|
296 } |
|
297 if (arr2.Length() != 9) { |
|
298 fail("RemoveElementAt should remove exactly one object"); |
|
299 } |
|
300 |
|
301 arr2.RemoveElement(ninthElement); |
|
302 if (Bar::sReleaseCalled != base + 12) { |
|
303 fail("Release called multiple times for RemoveElement"); |
|
304 } |
|
305 if (arr2.Length() != 8) { |
|
306 fail("RemoveElement should remove exactly one object"); |
|
307 } |
|
308 |
|
309 arr2.RemoveElementsAt(2, 3); |
|
310 if (Bar::sReleaseCalled != base + 15) { |
|
311 fail("Release called more or less than three times for RemoveElementsAt"); |
|
312 } |
|
313 if (arr2.Length() != 5) { |
|
314 fail("RemoveElementsAt should remove exactly three objects"); |
|
315 } |
|
316 for (uint32_t j = 0; j < arr2.Length(); ++j) { |
|
317 if (arr2.ElementAt(j) == thirdElement) { |
|
318 fail("RemoveElementsAt should have removed thirdElement"); |
|
319 } |
|
320 if (arr2.ElementAt(j) == fourthElement) { |
|
321 fail("RemoveElementsAt should have removed fourthElement"); |
|
322 } |
|
323 if (arr2.ElementAt(j) == fifthElement) { |
|
324 fail("RemoveElementsAt should have removed fifthElement"); |
|
325 } |
|
326 } |
|
327 |
|
328 arr2.RemoveElementsAt(4, 1); |
|
329 if (Bar::sReleaseCalled != base + 16) { |
|
330 fail("Release called more or less than one time for RemoveElementsAt"); |
|
331 } |
|
332 if (arr2.Length() != 4) { |
|
333 fail("RemoveElementsAt should work for removing the last element"); |
|
334 } |
|
335 |
|
336 arr2.Clear(); |
|
337 if (Bar::sReleaseCalled != base + 20) { |
|
338 fail("Release called multiple times for Clear"); |
|
339 } |
|
340 } |
|
341 |
|
342 Bar::sReleaseCalled = 0; |
|
343 |
|
344 { |
|
345 Array2 arr2; |
|
346 |
|
347 for (int32_t i = 0; i < 20; ++i) { |
|
348 nsCOMPtr<IBar> bar = new Bar(arr2); |
|
349 arr2.AppendObject(bar); |
|
350 } |
|
351 |
|
352 base = Bar::sReleaseCalled; |
|
353 |
|
354 // Let arr2 be destroyed |
|
355 } |
|
356 if (Bar::sReleaseCalled != base + 20) { |
|
357 fail("Release called multiple times for nsCOMArray::~nsCOMArray"); |
|
358 } |
|
359 |
|
360 return rv; |
|
361 } |