Back to index

lightning-sunbird  0.9+nobinonly
TestTArray.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is C++ array template tests.
00017  *
00018  * The Initial Developer of the Original Code is Google Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Darin Fisher <darin@meer.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include "nsTArray.h"
00042 #include "nsMemory.h"
00043 #include "nsAutoPtr.h"
00044 #include "nsString.h"
00045 #include "nsDirectoryServiceDefs.h"
00046 #include "nsDirectoryServiceUtils.h"
00047 #include "nsComponentManagerUtils.h"
00048 #include "nsXPCOM.h"
00049 #include "nsILocalFile.h"
00050 
00051 // Define this so we can use test_basic_array in test_comptr_array
00052 template <class T>
00053 inline bool operator<(const nsCOMPtr<T>& lhs, const nsCOMPtr<T>& rhs) {
00054   return lhs.get() < rhs.get();
00055 }
00056 
00057 //----
00058 
00059 template <class ElementType>
00060 static PRBool test_basic_array(ElementType *data,
00061                                PRUint32 dataLen,
00062                                const ElementType& extra) {
00063   nsTArray<ElementType> ary;
00064   ary.AppendElements(data, dataLen);
00065   PRUint32 i;
00066   for (i = 0; i < ary.Length(); ++i) {
00067     if (ary[i] != data[i])
00068       return PR_FALSE;
00069   }
00070   // ensure sort results in ascending order
00071   ary.Sort();
00072   for (i = 1; i < ary.Length(); ++i) {
00073     if (ary[i] < ary[i-1])
00074       return PR_FALSE;
00075   }
00076   PRUint32 oldLen = ary.Length();
00077   ary.RemoveElement(data[dataLen / 2]);
00078   if (ary.Length() != (oldLen - 1))
00079     return PR_FALSE;
00080 
00081   PRUint32 index = ary.Length() / 2;
00082   if (!ary.InsertElementAt(index, extra))
00083     return PR_FALSE;
00084   if (ary[index] != extra)
00085     return PR_FALSE;
00086   if (ary.IndexOf(extra) == PR_UINT32_MAX)
00087     return PR_FALSE;
00088   if (ary.LastIndexOf(extra) == PR_UINT32_MAX)
00089     return PR_FALSE;
00090   // ensure proper searching
00091   if (ary.IndexOf(extra) > ary.LastIndexOf(extra))
00092     return PR_FALSE;
00093   if (ary.IndexOf(extra, index) != ary.LastIndexOf(extra, index))
00094     return PR_FALSE;
00095 
00096   nsTArray<ElementType> copy(ary);
00097   for (i = 0; i < copy.Length(); ++i) {
00098     if (ary[i] != copy[i])
00099       return PR_FALSE;
00100   }
00101   if (!ary.AppendElements(copy))
00102     return PR_FALSE;
00103   PRUint32 cap = ary.Capacity();
00104   ary.RemoveElementsAt(copy.Length(), copy.Length());
00105   ary.Compact();
00106   if (ary.Capacity() == cap)
00107     return PR_FALSE;
00108 
00109   ary.Clear();
00110   if (!ary.IsEmpty() || ary.Elements() == nsnull)
00111     return PR_FALSE;
00112 
00113   ary = copy;
00114   for (i = 0; i < copy.Length(); ++i) {
00115     if (ary[i] != copy[i])
00116       return PR_FALSE;
00117   }
00118 
00119   if (!ary.InsertElementsAt(0, copy))
00120     return PR_FALSE;
00121   ary.RemoveElementsAt(0, copy.Length());
00122   for (i = 0; i < copy.Length(); ++i) {
00123     if (ary[i] != copy[i])
00124       return PR_FALSE;
00125   }
00126 
00127   // These shouldn't crash!
00128   nsTArray<ElementType> empty;
00129   ary.AppendElements(NS_REINTERPRET_CAST(ElementType *, 0), 0);
00130   ary.AppendElements(empty);
00131 
00132   // See bug 324981
00133   ary.RemoveElement(extra);
00134   ary.RemoveElement(extra);
00135 
00136   return PR_TRUE;
00137 }
00138 
00139 static PRBool test_int_array() {
00140   int data[] = {4,6,8,2,4,1,5,7,3};
00141   return test_basic_array(data, NS_ARRAY_LENGTH(data), int(14));
00142 }
00143 
00144 static PRBool test_int64_array() {
00145   PRInt64 data[] = {4,6,8,2,4,1,5,7,3};
00146   return test_basic_array(data, NS_ARRAY_LENGTH(data), PRInt64(14));
00147 }
00148 
00149 static PRBool test_char_array() {
00150   char data[] = {4,6,8,2,4,1,5,7,3};
00151   return test_basic_array(data, NS_ARRAY_LENGTH(data), char(14));
00152 }
00153 
00154 static PRBool test_uint32_array() {
00155   PRUint32 data[] = {4,6,8,2,4,1,5,7,3};
00156   return test_basic_array(data, NS_ARRAY_LENGTH(data), PRUint32(14));
00157 }
00158 
00159 //----
00160 
00161 class Object {
00162   public:
00163     Object() : mNum(0) {
00164     }
00165     Object(const char *str, PRUint32 num) : mStr(str), mNum(num) {
00166     }
00167     Object(const Object& other) : mStr(other.mStr), mNum(other.mNum) {
00168     }
00169     ~Object() {}
00170 
00171     Object& operator=(const Object& other) {
00172       mStr = other.mStr;
00173       mNum = other.mNum;
00174       return *this;
00175     }
00176 
00177     PRBool operator==(const Object& other) const {
00178       return mStr == other.mStr && mNum == other.mNum;
00179     }
00180 
00181     PRBool operator<(const Object& other) const {
00182       // sort based on mStr only
00183       return Compare(mStr, other.mStr) < 0;
00184     }
00185 
00186     const char *Str() const { return mStr.get(); }
00187     PRUint32 Num() const { return mNum; }
00188 
00189   private:
00190     nsCString mStr;
00191     PRUint32  mNum;
00192 };
00193 
00194 static PRBool test_object_array() {
00195   nsTArray<Object> objArray;
00196   const char kdata[] = "hello world";
00197   PRUint32 i;
00198   for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
00199     char x[] = {kdata[i],'\0'};
00200     if (!objArray.AppendElement(Object(x, i)))
00201       return PR_FALSE;
00202   }
00203   for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
00204     if (objArray[i].Str()[0] != kdata[i])
00205       return PR_FALSE;
00206     if (objArray[i].Num() != i)
00207       return PR_FALSE;
00208   }
00209   objArray.Sort();
00210   const char ksorted[] = "\0 dehllloorw";
00211   for (i = 0; i < NS_ARRAY_LENGTH(kdata)-1; ++i) {
00212     if (objArray[i].Str()[0] != ksorted[i])
00213       return PR_FALSE;
00214   }
00215   return PR_TRUE;
00216 }
00217 
00218 // nsTArray<nsAutoPtr<T>> is not supported
00219 #if 0
00220 static PRBool test_autoptr_array() {
00221   nsTArray< nsAutoPtr<Object> > objArray;
00222   const char kdata[] = "hello world";
00223   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
00224     char x[] = {kdata[i],'\0'};
00225     nsAutoPtr<Object> obj(new Object(x,i));
00226     if (!objArray.AppendElement(obj))  // XXX does not call copy-constructor for nsAutoPtr!!!
00227       return PR_FALSE;
00228     if (obj.get() == nsnull)
00229       return PR_FALSE;
00230     obj.forget();  // the array now owns the reference
00231   }
00232   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
00233     if (objArray[i]->Str()[0] != kdata[i])
00234       return PR_FALSE;
00235     if (objArray[i]->Num() != i)
00236       return PR_FALSE;
00237   }
00238   return PR_TRUE;
00239 }
00240 #endif
00241 
00242 //----
00243 
00244 static PRBool operator==(const nsCString &a, const char *b) {
00245   return a.Equals(b);
00246 }
00247 
00248 static PRBool test_string_array() {
00249   nsTArray<nsCString> strArray;
00250   const char kdata[] = "hello world";
00251   PRUint32 i;
00252   for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
00253     if (!strArray.AppendElement(nsCString(kdata[i])))
00254       return PR_FALSE;
00255   }
00256   for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
00257     if (strArray[i].CharAt(0) != kdata[i])
00258       return PR_FALSE;
00259   }
00260 
00261   const char kextra[] = "foo bar";
00262   PRUint32 oldLen = strArray.Length();
00263   if (!strArray.AppendElement(kextra))
00264     return PR_FALSE;
00265   strArray.RemoveElement(kextra);
00266   if (oldLen != strArray.Length())
00267     return PR_FALSE;
00268 
00269   if (strArray.IndexOf("e") != 1)
00270     return PR_FALSE;
00271 
00272   strArray.Sort();
00273   const char ksorted[] = "\0 dehllloorw";
00274   for (i = 0; i < NS_ARRAY_LENGTH(kdata)-1; ++i) {
00275     if (strArray[i].CharAt(0) != ksorted[i])
00276       return PR_FALSE;
00277   }
00278 
00279   nsCString rawArray[NS_ARRAY_LENGTH(kdata)-1];
00280   for (i = 0; i < NS_ARRAY_LENGTH(rawArray); ++i)
00281     rawArray[i].Assign(kdata + i);  // substrings of kdata
00282   return test_basic_array(rawArray, NS_ARRAY_LENGTH(rawArray),
00283                           nsCString("foopy"));
00284 }
00285 
00286 //----
00287 
00288 typedef nsCOMPtr<nsIFile> FilePointer;
00289 
00290 class nsFileNameComparator {
00291   public:
00292     PRBool Equals(const FilePointer &a, const char *b) const {
00293       nsCAutoString name;
00294       a->GetNativeLeafName(name);
00295       return name.Equals(b);
00296     }
00297 };
00298 
00299 static PRBool test_comptr_array() {
00300   FilePointer tmpDir;
00301   NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
00302   if (!tmpDir)
00303     return PR_FALSE;
00304   const char *kNames[] = {
00305     "foo.txt", "bar.html", "baz.gif"
00306   };
00307   nsTArray<FilePointer> fileArray;
00308   PRUint32 i;
00309   for (i = 0; i < NS_ARRAY_LENGTH(kNames); ++i) {
00310     FilePointer f;
00311     tmpDir->Clone(getter_AddRefs(f));
00312     if (!f)
00313       return PR_FALSE;
00314     if (NS_FAILED(f->AppendNative(nsDependentCString(kNames[i]))))
00315       return PR_FALSE;
00316     fileArray.AppendElement(f);
00317   }
00318 
00319   if (fileArray.IndexOf(kNames[1], 0, nsFileNameComparator()) != 1)
00320     return PR_FALSE;
00321 
00322   // It's unclear what 'operator<' means for nsCOMPtr, but whatever...
00323   return test_basic_array(fileArray.Elements(), fileArray.Length(), 
00324                           tmpDir);
00325 }
00326 
00327 //----
00328 
00329 class RefcountedObject {
00330   public:
00331     RefcountedObject() : rc(0) {}
00332     void AddRef() {
00333       ++rc;
00334     }
00335     void Release() {
00336       if (--rc == 0)
00337         delete this;
00338     }
00339     ~RefcountedObject() {}
00340   private:
00341     PRInt32 rc;
00342 };
00343 
00344 static PRBool test_refptr_array() {
00345   PRBool rv = PR_TRUE;
00346 
00347   nsTArray< nsRefPtr<RefcountedObject> > objArray;
00348 
00349   RefcountedObject *a = new RefcountedObject(); a->AddRef();
00350   RefcountedObject *b = new RefcountedObject(); b->AddRef();
00351   RefcountedObject *c = new RefcountedObject(); c->AddRef();
00352 
00353   objArray.AppendElement(a);
00354   objArray.AppendElement(b);
00355   objArray.AppendElement(c);
00356 
00357   if (objArray.IndexOf(b) != 1)
00358     rv = PR_FALSE;
00359 
00360   a->Release();
00361   b->Release();
00362   c->Release();
00363   return rv;
00364 }
00365 
00366 //----
00367 
00368 typedef PRBool (*TestFunc)();
00369 #define DECL_TEST(name) { #name, name }
00370 
00371 static const struct Test {
00372   const char* name;
00373   TestFunc    func;
00374 } tests[] = {
00375   DECL_TEST(test_int_array),
00376   DECL_TEST(test_int64_array),
00377   DECL_TEST(test_char_array),
00378   DECL_TEST(test_uint32_array),
00379   DECL_TEST(test_object_array),
00380   DECL_TEST(test_string_array),
00381   DECL_TEST(test_comptr_array),
00382   DECL_TEST(test_refptr_array),
00383   { nsnull, nsnull }
00384 };
00385 
00386 int main(int argc, char **argv) {
00387   int count = 1;
00388   if (argc > 1)
00389     count = atoi(argv[1]);
00390 
00391   if (NS_FAILED(NS_InitXPCOM2(nsnull, nsnull, nsnull)))
00392     return -1;
00393 
00394   while (count--) {
00395     for (const Test* t = tests; t->name != nsnull; ++t) {
00396       printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE");
00397     }
00398   }
00399   
00400   NS_ShutdownXPCOM(nsnull);
00401   return 0;
00402 }