1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=4:et:sw=4:
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2010
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "TestHarness.h"
39 : #include "nsCOMArray.h"
40 :
41 : // {9e70a320-be02-11d1-8031-006008159b5a}
42 : #define NS_IFOO_IID \
43 : {0x9e70a320, 0xbe02, 0x11d1, \
44 : {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
45 :
46 20 : class IFoo : public nsISupports {
47 : public:
48 :
49 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
50 :
51 : NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
52 : NS_IMETHOD_(PRInt32) ID() = 0;
53 : };
54 :
55 : NS_DEFINE_STATIC_IID_ACCESSOR(IFoo, NS_IFOO_IID)
56 :
57 : class Foo : public IFoo {
58 : public:
59 :
60 : Foo(PRInt32 aID);
61 : ~Foo();
62 :
63 : // nsISupports implementation
64 : NS_DECL_ISUPPORTS
65 :
66 : // IFoo implementation
67 0 : NS_IMETHOD_(nsrefcnt) RefCnt() { return mRefCnt; }
68 0 : NS_IMETHOD_(PRInt32) ID() { return mID; }
69 :
70 : static PRInt32 gCount;
71 :
72 : PRInt32 mID;
73 : };
74 :
75 : PRInt32 Foo::gCount = 0;
76 :
77 20 : Foo::Foo(PRInt32 aID)
78 : {
79 20 : mID = aID;
80 20 : ++gCount;
81 20 : }
82 :
83 20 : Foo::~Foo()
84 : {
85 20 : --gCount;
86 20 : }
87 :
88 160 : NS_IMPL_ISUPPORTS1(Foo, IFoo)
89 :
90 :
91 : typedef nsCOMArray<IFoo> Array;
92 :
93 :
94 : // {0e70a320-be02-11d1-8031-006008159b5a}
95 : #define NS_IBAR_IID \
96 : {0x0e70a320, 0xbe02, 0x11d1, \
97 : {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
98 :
99 40 : class IBar : public nsISupports {
100 : public:
101 :
102 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_IBAR_IID)
103 : };
104 :
105 : NS_DEFINE_STATIC_IID_ACCESSOR(IBar, NS_IBAR_IID)
106 :
107 : class Bar : public IBar {
108 : public:
109 :
110 : explicit Bar(nsCOMArray<IBar>& aArray);
111 : ~Bar();
112 :
113 : // nsISupports implementation
114 : NS_DECL_ISUPPORTS
115 :
116 : static PRInt32 sReleaseCalled;
117 :
118 : private:
119 : nsCOMArray<IBar>& mArray;
120 : };
121 :
122 : PRInt32 Bar::sReleaseCalled = 0;
123 :
124 : typedef nsCOMArray<IBar> Array2;
125 :
126 40 : Bar::Bar(Array2& aArray)
127 40 : : mArray(aArray)
128 : {
129 40 : }
130 :
131 40 : Bar::~Bar()
132 : {
133 40 : if (mArray.RemoveObject(this)) {
134 0 : fail("We should never manage to remove the object here");
135 : }
136 40 : }
137 :
138 120 : NS_IMPL_ADDREF(Bar)
139 40 : NS_IMPL_QUERY_INTERFACE1(Bar, IBar)
140 :
141 : NS_IMETHODIMP_(nsrefcnt)
142 120 : Bar::Release(void)
143 : {
144 120 : ++Bar::sReleaseCalled;
145 120 : NS_PRECONDITION(0 != mRefCnt, "dup release");
146 120 : NS_ASSERT_OWNINGTHREAD(_class);
147 120 : --mRefCnt;
148 120 : NS_LOG_RELEASE(this, mRefCnt, "Bar");
149 120 : if (mRefCnt == 0) {
150 40 : mRefCnt = 1; /* stabilize */
151 40 : delete this;
152 40 : return 0;
153 : }
154 80 : return mRefCnt;
155 : }
156 :
157 :
158 1 : int main(int argc, char **argv)
159 : {
160 2 : ScopedXPCOM xpcom("nsCOMArrayTests");
161 1 : if (xpcom.failed()) {
162 0 : return 1;
163 : }
164 :
165 1 : int rv = 0;
166 :
167 2 : Array arr;
168 :
169 21 : for (PRInt32 i = 0; i < 20; ++i) {
170 40 : nsCOMPtr<IFoo> foo = new Foo(i);
171 20 : arr.AppendObject(foo);
172 : }
173 :
174 1 : if (arr.Count() != 20 || Foo::gCount != 20) {
175 0 : fail("nsCOMArray::AppendObject failed");
176 0 : rv = 1;
177 : }
178 :
179 1 : arr.SetCount(10);
180 :
181 1 : if (arr.Count() != 10 || Foo::gCount != 10) {
182 0 : fail("nsCOMArray::SetCount shortening of array failed");
183 0 : rv = 1;
184 : }
185 :
186 1 : arr.SetCount(30);
187 :
188 1 : if (arr.Count() != 30 || Foo::gCount != 10) {
189 0 : fail("nsCOMArray::SetCount lengthening of array failed");
190 0 : rv = 1;
191 : }
192 :
193 11 : for (PRInt32 i = 0; i < 10; ++i) {
194 10 : if (arr[i] == nsnull) {
195 0 : fail("nsCOMArray elements should be non-null");
196 0 : rv = 1;
197 0 : break;
198 : }
199 : }
200 :
201 21 : for (PRInt32 i = 10; i < 30; ++i) {
202 20 : if (arr[i] != nsnull) {
203 0 : fail("nsCOMArray elements should be null");
204 0 : rv = 1;
205 0 : break;
206 : }
207 : }
208 :
209 : PRInt32 base;
210 : {
211 2 : Array2 arr2;
212 :
213 : IBar *thirdObject,
214 : *fourthObject,
215 : *fifthObject,
216 : *ninthObject;
217 21 : for (PRInt32 i = 0; i < 20; ++i) {
218 40 : nsCOMPtr<IBar> bar = new Bar(arr2);
219 20 : switch (i) {
220 : case 2:
221 1 : thirdObject = bar; break;
222 : case 3:
223 1 : fourthObject = bar; break;
224 : case 4:
225 1 : fifthObject = bar; break;
226 : case 8:
227 1 : ninthObject = bar; break;
228 : }
229 20 : arr2.AppendObject(bar);
230 : }
231 :
232 1 : base = Bar::sReleaseCalled;
233 :
234 1 : arr2.SetCount(10);
235 1 : if (Bar::sReleaseCalled != base + 10) {
236 0 : fail("Release called multiple times for SetCount");
237 : }
238 1 : if (arr2.Count() != 10) {
239 0 : fail("SetCount(10) should remove exactly ten objects");
240 : }
241 :
242 1 : arr2.RemoveObjectAt(9);
243 1 : if (Bar::sReleaseCalled != base + 11) {
244 0 : fail("Release called multiple times for RemoveObjectAt");
245 : }
246 1 : if (arr2.Count() != 9) {
247 0 : fail("RemoveObjectAt should remove exactly one object");
248 : }
249 :
250 1 : arr2.RemoveObject(ninthObject);
251 1 : if (Bar::sReleaseCalled != base + 12) {
252 0 : fail("Release called multiple times for RemoveObject");
253 : }
254 1 : if (arr2.Count() != 8) {
255 0 : fail("RemoveObject should remove exactly one object");
256 : }
257 :
258 1 : arr2.RemoveObjectsAt(2, 3);
259 1 : if (Bar::sReleaseCalled != base + 15) {
260 0 : fail("Release called more or less than three times for RemoveObjectsAt");
261 : }
262 1 : if (arr2.Count() != 5) {
263 0 : fail("RemoveObjectsAt should remove exactly three objects");
264 : }
265 6 : for (PRInt32 j = 0; j < arr2.Count(); ++j) {
266 5 : if (arr2.ObjectAt(j) == thirdObject) {
267 0 : fail("RemoveObjectsAt should have removed thirdObject");
268 : }
269 5 : if (arr2.ObjectAt(j) == fourthObject) {
270 0 : fail("RemoveObjectsAt should have removed fourthObject");
271 : }
272 5 : if (arr2.ObjectAt(j) == fifthObject) {
273 0 : fail("RemoveObjectsAt should have removed fifthObject");
274 : }
275 : }
276 :
277 1 : arr2.RemoveObjectsAt(4, 1);
278 1 : if (Bar::sReleaseCalled != base + 16) {
279 0 : fail("Release called more or less than one time for RemoveObjectsAt");
280 : }
281 1 : if (arr2.Count() != 4) {
282 0 : fail("RemoveObjectsAt should work for removing the last element");
283 : }
284 :
285 1 : arr2.Clear();
286 1 : if (Bar::sReleaseCalled != base + 20) {
287 0 : fail("Release called multiple times for Clear");
288 : }
289 : }
290 :
291 1 : Bar::sReleaseCalled = 0;
292 :
293 : {
294 2 : Array2 arr2;
295 :
296 21 : for (PRInt32 i = 0; i < 20; ++i) {
297 40 : nsCOMPtr<IBar> bar = new Bar(arr2);
298 20 : arr2.AppendObject(bar);
299 : }
300 :
301 1 : base = Bar::sReleaseCalled;
302 :
303 : // Let arr2 be destroyed
304 : }
305 1 : if (Bar::sReleaseCalled != base + 20) {
306 0 : fail("Release called multiple times for nsCOMArray::~nsCOMArray");
307 : }
308 :
309 1 : return rv;
310 : }
|