1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsAtom.h"
#include "nsString.h"
#include "UTFStrings.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "gtest/gtest.h"
#include "mozilla/gtest/MozAssertions.h"
using namespace mozilla;
int32_t NS_GetUnusedAtomCount(void);
namespace TestAtoms {
TEST(Atoms, Basic)
{
for (unsigned int i = 0; i < std::size(ValidStrings); ++i) {
nsDependentString str16(ValidStrings[i].m16);
nsDependentCString str8(ValidStrings[i].m8);
RefPtr<nsAtom> atom = NS_Atomize(str16);
EXPECT_TRUE(atom->Equals(str16));
nsString tmp16;
nsCString tmp8;
atom->ToString(tmp16);
atom->ToUTF8String(tmp8);
EXPECT_TRUE(str16.Equals(tmp16));
EXPECT_TRUE(str8.Equals(tmp8));
EXPECT_TRUE(nsDependentString(atom->GetUTF16String()).Equals(str16));
EXPECT_TRUE(nsAtomString(atom).Equals(str16));
EXPECT_TRUE(nsDependentAtomString(atom).Equals(str16));
EXPECT_TRUE(nsAtomCString(atom).Equals(str8));
}
}
TEST(Atoms, 16vs8)
{
for (unsigned int i = 0; i < std::size(ValidStrings); ++i) {
RefPtr<nsAtom> atom16 = NS_Atomize(ValidStrings[i].m16);
RefPtr<nsAtom> atom8 = NS_Atomize(ValidStrings[i].m8);
EXPECT_EQ(atom16, atom8);
}
}
TEST(Atoms, Null)
{
nsAutoString str(u"string with a \0 char"_ns);
nsDependentString strCut(str.get());
EXPECT_FALSE(str.Equals(strCut));
RefPtr<nsAtom> atomCut = NS_Atomize(strCut);
RefPtr<nsAtom> atom = NS_Atomize(str);
EXPECT_EQ(atom->GetLength(), str.Length());
EXPECT_TRUE(atom->Equals(str));
EXPECT_NE(atom, atomCut);
EXPECT_TRUE(atomCut->Equals(strCut));
}
TEST(Atoms, Invalid)
{
for (unsigned int i = 0; i < std::size(Invalid16Strings); ++i) {
nsrefcnt count = NS_GetNumberOfAtoms();
{
RefPtr<nsAtom> atom16 = NS_Atomize(Invalid16Strings[i].m16);
EXPECT_TRUE(atom16->Equals(nsDependentString(Invalid16Strings[i].m16)));
}
EXPECT_EQ(count, NS_GetNumberOfAtoms());
}
#ifndef DEBUG
// Don't run this test in debug builds as that intentionally asserts.
for (unsigned int i = 0; i < std::size(Invalid8Strings); ++i) {
nsrefcnt count = NS_GetNumberOfAtoms();
{
RefPtr<nsAtom> atom8 = NS_Atomize(Invalid8Strings[i].m8);
RefPtr<nsAtom> atom16 = NS_Atomize(Invalid8Strings[i].m16);
EXPECT_EQ(atom16, atom8);
EXPECT_TRUE(atom16->Equals(nsDependentString(Invalid8Strings[i].m16)));
}
EXPECT_EQ(count, NS_GetNumberOfAtoms());
}
for (unsigned int i = 0; i < std::size(Malformed8Strings); ++i) {
nsrefcnt count = NS_GetNumberOfAtoms();
{
RefPtr<nsAtom> atom8 = NS_Atomize(Malformed8Strings[i].m8);
RefPtr<nsAtom> atom16 = NS_Atomize(Malformed8Strings[i].m16);
EXPECT_EQ(atom8, atom16);
}
EXPECT_EQ(count, NS_GetNumberOfAtoms());
}
#endif
}
#define FIRST_ATOM_STR "first static atom. Hello!"
#define SECOND_ATOM_STR "second static atom. @World!"
#define THIRD_ATOM_STR "third static atom?!"
static bool isStaticAtom(nsAtom* atom) {
// Don't use logic && in order to ensure that all addrefs/releases are always
// run, even if one of the tests fail. This allows us to run this code on a
// non-static atom without affecting its refcount.
bool rv = (atom->AddRef() == 2);
rv &= (atom->AddRef() == 2);
rv &= (atom->AddRef() == 2);
rv &= (atom->Release() == 1);
rv &= (atom->Release() == 1);
rv &= (atom->Release() == 1);
return rv;
}
TEST(Atoms, Table)
{
nsrefcnt count = NS_GetNumberOfAtoms();
RefPtr<nsAtom> thirdDynamic = NS_Atomize(THIRD_ATOM_STR);
EXPECT_FALSE(isStaticAtom(thirdDynamic));
EXPECT_TRUE(thirdDynamic);
EXPECT_EQ(NS_GetNumberOfAtoms(), count + 1);
}
static void AccessAtoms(void*) {
for (int i = 0; i < 10000; i++) {
RefPtr<nsAtom> atom = NS_Atomize(u"A Testing Atom");
}
}
TEST(Atoms, ConcurrentAccessing)
{
static const size_t kThreadCount = 4;
// Force a GC before so that we don't have any unused atom.
NS_GetNumberOfAtoms();
EXPECT_EQ(NS_GetUnusedAtomCount(), int32_t(0));
// Spawn PRThreads to do the concurrent atom access, to make sure we don't
// spin the main thread event loop. Spinning the event loop may run a task
// that uses an atom, leading to a false positive test failure.
PRThread* threads[kThreadCount];
for (size_t i = 0; i < kThreadCount; i++) {
threads[i] = PR_CreateThread(PR_USER_THREAD, AccessAtoms, nullptr,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0);
EXPECT_TRUE(threads[i]);
}
for (size_t i = 0; i < kThreadCount; i++) {
EXPECT_EQ(PR_SUCCESS, PR_JoinThread(threads[i]));
}
// We should have one unused atom from this test.
EXPECT_EQ(NS_GetUnusedAtomCount(), int32_t(1));
}
} // namespace TestAtoms
|