mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
560 lines
15 KiB
C++
560 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is C++ array template tests.
|
|
*
|
|
* The Initial Developer of the Original Code is Google Inc.
|
|
* Portions created by the Initial Developer are Copyright (C) 2005
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Darin Fisher <darin@meer.net>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "nsTArray.h"
|
|
#include "nsTPtrArray.h"
|
|
#include "nsMemory.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "nsString.h"
|
|
#include "nsDirectoryServiceDefs.h"
|
|
#include "nsDirectoryServiceUtils.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsXPCOM.h"
|
|
#include "nsILocalFile.h"
|
|
|
|
namespace TestTArray {
|
|
|
|
// Define this so we can use test_basic_array in test_comptr_array
|
|
template <class T>
|
|
inline bool operator<(const nsCOMPtr<T>& lhs, const nsCOMPtr<T>& rhs) {
|
|
return lhs.get() < rhs.get();
|
|
}
|
|
|
|
//----
|
|
|
|
template <class ElementType>
|
|
static PRBool test_basic_array(ElementType *data,
|
|
PRUint32 dataLen,
|
|
const ElementType& extra) {
|
|
nsTArray<ElementType> ary;
|
|
ary.AppendElements(data, dataLen);
|
|
if (ary.Length() != dataLen) {
|
|
return PR_FALSE;
|
|
}
|
|
PRUint32 i;
|
|
for (i = 0; i < ary.Length(); ++i) {
|
|
if (ary[i] != data[i])
|
|
return PR_FALSE;
|
|
}
|
|
for (i = 0; i < ary.Length(); ++i) {
|
|
if (ary.SafeElementAt(i, extra) != data[i])
|
|
return PR_FALSE;
|
|
}
|
|
if (ary.SafeElementAt(ary.Length(), extra) != extra ||
|
|
ary.SafeElementAt(ary.Length() * 10, extra) != extra)
|
|
return PR_FALSE;
|
|
// ensure sort results in ascending order
|
|
ary.Sort();
|
|
for (i = ary.Length(); --i; ) {
|
|
if (ary[i] < ary[i - 1])
|
|
return PR_FALSE;
|
|
if (ary[i] == ary[i - 1])
|
|
ary.RemoveElementAt(i);
|
|
}
|
|
for (i = 0; i < ary.Length(); ++i) {
|
|
if (ary.BinaryIndexOf(ary[i]) != i)
|
|
return PR_FALSE;
|
|
}
|
|
if (ary.BinaryIndexOf(extra) != -1)
|
|
return PR_FALSE;
|
|
PRUint32 oldLen = ary.Length();
|
|
ary.RemoveElement(data[dataLen / 2]);
|
|
if (ary.Length() != (oldLen - 1))
|
|
return PR_FALSE;
|
|
|
|
PRUint32 index = ary.Length() / 2;
|
|
if (!ary.InsertElementAt(index, extra))
|
|
return PR_FALSE;
|
|
if (ary[index] != extra)
|
|
return PR_FALSE;
|
|
if (ary.IndexOf(extra) == PR_UINT32_MAX)
|
|
return PR_FALSE;
|
|
if (ary.LastIndexOf(extra) == PR_UINT32_MAX)
|
|
return PR_FALSE;
|
|
// ensure proper searching
|
|
if (ary.IndexOf(extra) > ary.LastIndexOf(extra))
|
|
return PR_FALSE;
|
|
if (ary.IndexOf(extra, index) != ary.LastIndexOf(extra, index))
|
|
return PR_FALSE;
|
|
|
|
nsTArray<ElementType> copy(ary);
|
|
for (i = 0; i < copy.Length(); ++i) {
|
|
if (ary[i] != copy[i])
|
|
return PR_FALSE;
|
|
}
|
|
if (!ary.AppendElements(copy))
|
|
return PR_FALSE;
|
|
PRUint32 cap = ary.Capacity();
|
|
ary.RemoveElementsAt(copy.Length(), copy.Length());
|
|
ary.Compact();
|
|
if (ary.Capacity() == cap)
|
|
return PR_FALSE;
|
|
|
|
ary.Clear();
|
|
if (!ary.IsEmpty() || ary.Elements() == nsnull)
|
|
return PR_FALSE;
|
|
if (ary.SafeElementAt(0, extra) != extra ||
|
|
ary.SafeElementAt(10, extra) != extra)
|
|
return PR_FALSE;
|
|
|
|
ary = copy;
|
|
for (i = 0; i < copy.Length(); ++i) {
|
|
if (ary[i] != copy[i])
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if (!ary.InsertElementsAt(0, copy))
|
|
return PR_FALSE;
|
|
ary.RemoveElementsAt(0, copy.Length());
|
|
for (i = 0; i < copy.Length(); ++i) {
|
|
if (ary[i] != copy[i])
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// These shouldn't crash!
|
|
nsTArray<ElementType> empty;
|
|
ary.AppendElements(reinterpret_cast<ElementType *>(0), 0);
|
|
ary.AppendElements(empty);
|
|
|
|
// See bug 324981
|
|
ary.RemoveElement(extra);
|
|
ary.RemoveElement(extra);
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
static PRBool test_int_array() {
|
|
int data[] = {4,6,8,2,4,1,5,7,3};
|
|
return test_basic_array(data, NS_ARRAY_LENGTH(data), int(14));
|
|
}
|
|
|
|
static PRBool test_int64_array() {
|
|
PRInt64 data[] = {4,6,8,2,4,1,5,7,3};
|
|
return test_basic_array(data, NS_ARRAY_LENGTH(data), PRInt64(14));
|
|
}
|
|
|
|
static PRBool test_char_array() {
|
|
char data[] = {4,6,8,2,4,1,5,7,3};
|
|
return test_basic_array(data, NS_ARRAY_LENGTH(data), char(14));
|
|
}
|
|
|
|
static PRBool test_uint32_array() {
|
|
PRUint32 data[] = {4,6,8,2,4,1,5,7,3};
|
|
return test_basic_array(data, NS_ARRAY_LENGTH(data), PRUint32(14));
|
|
}
|
|
|
|
//----
|
|
|
|
class Object {
|
|
public:
|
|
Object() : mNum(0) {
|
|
}
|
|
Object(const char *str, PRUint32 num) : mStr(str), mNum(num) {
|
|
}
|
|
Object(const Object& other) : mStr(other.mStr), mNum(other.mNum) {
|
|
}
|
|
~Object() {}
|
|
|
|
Object& operator=(const Object& other) {
|
|
mStr = other.mStr;
|
|
mNum = other.mNum;
|
|
return *this;
|
|
}
|
|
|
|
PRBool operator==(const Object& other) const {
|
|
return mStr == other.mStr && mNum == other.mNum;
|
|
}
|
|
|
|
PRBool operator<(const Object& other) const {
|
|
// sort based on mStr only
|
|
return Compare(mStr, other.mStr) < 0;
|
|
}
|
|
|
|
const char *Str() const { return mStr.get(); }
|
|
PRUint32 Num() const { return mNum; }
|
|
|
|
private:
|
|
nsCString mStr;
|
|
PRUint32 mNum;
|
|
};
|
|
|
|
static PRBool test_object_array() {
|
|
nsTArray<Object> objArray;
|
|
const char kdata[] = "hello world";
|
|
PRUint32 i;
|
|
for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
|
|
char x[] = {kdata[i],'\0'};
|
|
if (!objArray.AppendElement(Object(x, i)))
|
|
return PR_FALSE;
|
|
}
|
|
for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
|
|
if (objArray[i].Str()[0] != kdata[i])
|
|
return PR_FALSE;
|
|
if (objArray[i].Num() != i)
|
|
return PR_FALSE;
|
|
}
|
|
objArray.Sort();
|
|
const char ksorted[] = "\0 dehllloorw";
|
|
for (i = 0; i < NS_ARRAY_LENGTH(kdata)-1; ++i) {
|
|
if (objArray[i].Str()[0] != ksorted[i])
|
|
return PR_FALSE;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
// nsTArray<nsAutoPtr<T>> is not supported
|
|
#if 0
|
|
static PRBool test_autoptr_array() {
|
|
nsTArray< nsAutoPtr<Object> > objArray;
|
|
const char kdata[] = "hello world";
|
|
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
|
|
char x[] = {kdata[i],'\0'};
|
|
nsAutoPtr<Object> obj(new Object(x,i));
|
|
if (!objArray.AppendElement(obj)) // XXX does not call copy-constructor for nsAutoPtr!!!
|
|
return PR_FALSE;
|
|
if (obj.get() == nsnull)
|
|
return PR_FALSE;
|
|
obj.forget(); // the array now owns the reference
|
|
}
|
|
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
|
|
if (objArray[i]->Str()[0] != kdata[i])
|
|
return PR_FALSE;
|
|
if (objArray[i]->Num() != i)
|
|
return PR_FALSE;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
#endif
|
|
|
|
//----
|
|
|
|
static PRBool operator==(const nsCString &a, const char *b) {
|
|
return a.Equals(b);
|
|
}
|
|
|
|
static PRBool test_string_array() {
|
|
nsTArray<nsCString> strArray;
|
|
const char kdata[] = "hello world";
|
|
PRUint32 i;
|
|
for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
|
|
if (!strArray.AppendElement(nsCString(kdata[i])))
|
|
return PR_FALSE;
|
|
}
|
|
for (i = 0; i < NS_ARRAY_LENGTH(kdata); ++i) {
|
|
if (strArray[i].CharAt(0) != kdata[i])
|
|
return PR_FALSE;
|
|
}
|
|
|
|
const char kextra[] = "foo bar";
|
|
PRUint32 oldLen = strArray.Length();
|
|
if (!strArray.AppendElement(kextra))
|
|
return PR_FALSE;
|
|
strArray.RemoveElement(kextra);
|
|
if (oldLen != strArray.Length())
|
|
return PR_FALSE;
|
|
|
|
if (strArray.IndexOf("e") != 1)
|
|
return PR_FALSE;
|
|
|
|
strArray.Sort();
|
|
const char ksorted[] = "\0 dehllloorw";
|
|
for (i = NS_ARRAY_LENGTH(kdata); i--; ) {
|
|
if (strArray[i].CharAt(0) != ksorted[i])
|
|
return PR_FALSE;
|
|
if (i > 0 && strArray[i] == strArray[i - 1])
|
|
strArray.RemoveElementAt(i);
|
|
}
|
|
for (i = 0; i < strArray.Length(); ++i) {
|
|
if (strArray.BinaryIndexOf(strArray[i]) != i)
|
|
return PR_FALSE;
|
|
}
|
|
if (strArray.BinaryIndexOf(EmptyCString()) != -1)
|
|
return PR_FALSE;
|
|
|
|
nsCString rawArray[NS_ARRAY_LENGTH(kdata)-1];
|
|
for (i = 0; i < NS_ARRAY_LENGTH(rawArray); ++i)
|
|
rawArray[i].Assign(kdata + i); // substrings of kdata
|
|
return test_basic_array(rawArray, NS_ARRAY_LENGTH(rawArray),
|
|
nsCString("foopy"));
|
|
}
|
|
|
|
//----
|
|
|
|
typedef nsCOMPtr<nsIFile> FilePointer;
|
|
|
|
class nsFileNameComparator {
|
|
public:
|
|
PRBool Equals(const FilePointer &a, const char *b) const {
|
|
nsCAutoString name;
|
|
a->GetNativeLeafName(name);
|
|
return name.Equals(b);
|
|
}
|
|
};
|
|
|
|
static PRBool test_comptr_array() {
|
|
FilePointer tmpDir;
|
|
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
|
|
if (!tmpDir)
|
|
return PR_FALSE;
|
|
const char *kNames[] = {
|
|
"foo.txt", "bar.html", "baz.gif"
|
|
};
|
|
nsTArray<FilePointer> fileArray;
|
|
PRUint32 i;
|
|
for (i = 0; i < NS_ARRAY_LENGTH(kNames); ++i) {
|
|
FilePointer f;
|
|
tmpDir->Clone(getter_AddRefs(f));
|
|
if (!f)
|
|
return PR_FALSE;
|
|
if (NS_FAILED(f->AppendNative(nsDependentCString(kNames[i]))))
|
|
return PR_FALSE;
|
|
fileArray.AppendElement(f);
|
|
}
|
|
|
|
if (fileArray.IndexOf(kNames[1], 0, nsFileNameComparator()) != 1)
|
|
return PR_FALSE;
|
|
|
|
// It's unclear what 'operator<' means for nsCOMPtr, but whatever...
|
|
return test_basic_array(fileArray.Elements(), fileArray.Length(),
|
|
tmpDir);
|
|
}
|
|
|
|
//----
|
|
|
|
class RefcountedObject {
|
|
public:
|
|
RefcountedObject() : rc(0) {}
|
|
void AddRef() {
|
|
++rc;
|
|
}
|
|
void Release() {
|
|
if (--rc == 0)
|
|
delete this;
|
|
}
|
|
~RefcountedObject() {}
|
|
private:
|
|
PRInt32 rc;
|
|
};
|
|
|
|
static PRBool test_refptr_array() {
|
|
PRBool rv = PR_TRUE;
|
|
|
|
nsTArray< nsRefPtr<RefcountedObject> > objArray;
|
|
|
|
RefcountedObject *a = new RefcountedObject(); a->AddRef();
|
|
RefcountedObject *b = new RefcountedObject(); b->AddRef();
|
|
RefcountedObject *c = new RefcountedObject(); c->AddRef();
|
|
|
|
objArray.AppendElement(a);
|
|
objArray.AppendElement(b);
|
|
objArray.AppendElement(c);
|
|
|
|
if (objArray.IndexOf(b) != 1)
|
|
rv = PR_FALSE;
|
|
|
|
a->Release();
|
|
b->Release();
|
|
c->Release();
|
|
return rv;
|
|
}
|
|
|
|
//----
|
|
|
|
static PRBool test_ptrarray() {
|
|
nsTPtrArray<PRUint32> ary;
|
|
if (ary.SafeElementAt(0) != nsnull)
|
|
return PR_FALSE;
|
|
if (ary.SafeElementAt(1000) != nsnull)
|
|
return PR_FALSE;
|
|
PRUint32 a = 10;
|
|
ary.AppendElement(&a);
|
|
if (*ary[0] != a)
|
|
return PR_FALSE;
|
|
if (*ary.SafeElementAt(0) != a)
|
|
return PR_FALSE;
|
|
|
|
nsTPtrArray<const PRUint32> cary;
|
|
if (cary.SafeElementAt(0) != nsnull)
|
|
return PR_FALSE;
|
|
if (cary.SafeElementAt(1000) != nsnull)
|
|
return PR_FALSE;
|
|
const PRUint32 b = 14;
|
|
cary.AppendElement(&a);
|
|
cary.AppendElement(&b);
|
|
if (*cary[0] != a || *cary[1] != b)
|
|
return PR_FALSE;
|
|
if (*cary.SafeElementAt(0) != a || *cary.SafeElementAt(1) != b)
|
|
return PR_FALSE;
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
//----
|
|
|
|
// This test relies too heavily on the existance of DebugGetHeader to be
|
|
// useful in non-debug builds.
|
|
#ifdef DEBUG
|
|
static PRBool test_autoarray() {
|
|
PRUint32 data[] = {4,6,8,2,4,1,5,7,3};
|
|
nsAutoTArray<PRUint32, NS_ARRAY_LENGTH(data)> array;
|
|
|
|
void* hdr = array.DebugGetHeader();
|
|
if (hdr == nsTArray<PRUint32>().DebugGetHeader())
|
|
return PR_FALSE;
|
|
if (hdr == nsAutoTArray<PRUint32, NS_ARRAY_LENGTH(data)>().DebugGetHeader())
|
|
return PR_FALSE;
|
|
|
|
array.AppendElement(1u);
|
|
if (hdr != array.DebugGetHeader())
|
|
return PR_FALSE;
|
|
|
|
array.RemoveElement(1u);
|
|
array.AppendElements(data, NS_ARRAY_LENGTH(data));
|
|
if (hdr != array.DebugGetHeader())
|
|
return PR_FALSE;
|
|
|
|
array.AppendElement(2u);
|
|
if (hdr == array.DebugGetHeader())
|
|
return PR_FALSE;
|
|
|
|
array.Clear();
|
|
array.Compact();
|
|
if (hdr != array.DebugGetHeader())
|
|
return PR_FALSE;
|
|
array.AppendElements(data, NS_ARRAY_LENGTH(data));
|
|
if (hdr != array.DebugGetHeader())
|
|
return PR_FALSE;
|
|
|
|
nsTArray<PRUint32> array2;
|
|
void* emptyHdr = array2.DebugGetHeader();
|
|
array.SwapElements(array2);
|
|
if (emptyHdr == array.DebugGetHeader())
|
|
return PR_FALSE;
|
|
if (hdr == array2.DebugGetHeader())
|
|
return PR_FALSE;
|
|
PRUint32 i;
|
|
for (i = 0; i < NS_ARRAY_LENGTH(data); ++i) {
|
|
if (array2[i] != data[i])
|
|
return PR_FALSE;
|
|
}
|
|
if (!array.IsEmpty())
|
|
return PR_FALSE;
|
|
|
|
array.Compact();
|
|
array.AppendElements(data, NS_ARRAY_LENGTH(data));
|
|
PRUint32 data3[] = {5, 7, 11};
|
|
nsAutoTArray<PRUint32, NS_ARRAY_LENGTH(data3)> array3;
|
|
array3.AppendElements(data3, NS_ARRAY_LENGTH(data3));
|
|
array.SwapElements(array3);
|
|
for (i = 0; i < NS_ARRAY_LENGTH(data); ++i) {
|
|
if (array3[i] != data[i])
|
|
return PR_FALSE;
|
|
}
|
|
for (i = 0; i < NS_ARRAY_LENGTH(data3); ++i) {
|
|
if (array[i] != data3[i])
|
|
return PR_FALSE;
|
|
}
|
|
|
|
return PR_TRUE;
|
|
}
|
|
#endif
|
|
|
|
//----
|
|
|
|
// IndexOf used to potentially scan beyond the end of the array. Test for
|
|
// this incorrect behavior by adding a value (5), removing it, then seeing
|
|
// if IndexOf finds it.
|
|
static PRBool test_indexof() {
|
|
nsTArray<int> array;
|
|
array.AppendElement(0);
|
|
// add and remove the 5
|
|
array.AppendElement(5);
|
|
array.RemoveElementAt(1);
|
|
// we should not find the 5!
|
|
return array.IndexOf(5, 1) == -1;
|
|
}
|
|
|
|
//----
|
|
|
|
typedef PRBool (*TestFunc)();
|
|
#define DECL_TEST(name) { #name, name }
|
|
|
|
static const struct Test {
|
|
const char* name;
|
|
TestFunc func;
|
|
} tests[] = {
|
|
DECL_TEST(test_int_array),
|
|
DECL_TEST(test_int64_array),
|
|
DECL_TEST(test_char_array),
|
|
DECL_TEST(test_uint32_array),
|
|
DECL_TEST(test_object_array),
|
|
DECL_TEST(test_string_array),
|
|
DECL_TEST(test_comptr_array),
|
|
DECL_TEST(test_refptr_array),
|
|
DECL_TEST(test_ptrarray),
|
|
#ifdef DEBUG
|
|
DECL_TEST(test_autoarray),
|
|
#endif
|
|
DECL_TEST(test_indexof),
|
|
{ nsnull, nsnull }
|
|
};
|
|
|
|
}
|
|
|
|
using namespace TestTArray;
|
|
|
|
int main(int argc, char **argv) {
|
|
int count = 1;
|
|
if (argc > 1)
|
|
count = atoi(argv[1]);
|
|
|
|
if (NS_FAILED(NS_InitXPCOM2(nsnull, nsnull, nsnull)))
|
|
return -1;
|
|
|
|
while (count--) {
|
|
for (const Test* t = tests; t->name != nsnull; ++t) {
|
|
printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE");
|
|
}
|
|
}
|
|
|
|
NS_ShutdownXPCOM(nsnull);
|
|
return 0;
|
|
}
|