Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/cont/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ ROOT_ADD_GTEST(TSeqTests TSeqTests.cxx LIBRARIES Core)
ROOT_ADD_GTEST(testIter testIter.cxx LIBRARIES Core)
ROOT_ADD_GTEST(TListTest TListTest.cxx LIBRARIES Core)
ROOT_ADD_GTEST(THashListTest THashListTest.cxx LIBRARIES Core)
ROOT_ADD_GTEST(TObjArrayTest TObjArrayTest.cxx LIBRARIES Core)
317 changes: 317 additions & 0 deletions core/cont/test/TObjArrayTest.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
#include "gtest/gtest.h"
#include "TNamed.h"
#include "TObjArray.h"

namespace {
class TrackObject : public TObject {
public:
static int fgCount;
TrackObject() { fgCount++; }
~TrackObject() override { fgCount--; }
};
int TrackObject::fgCount = 0;
} // namespace

TEST(TObjArrayTest, DefaultConstructor)
{
TObjArray array;
EXPECT_EQ(array.GetEntries(), 0);
EXPECT_EQ(array.GetEntriesFast(), 0);
EXPECT_EQ(array.GetLast(), -1);
EXPECT_TRUE(array.IsEmpty());
}

TEST(TObjArrayTest, AddAndAt)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");

array.Add(s1);
array.Add(s2);

EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.GetLast(), 1);
EXPECT_FALSE(array.IsEmpty());

EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), s2);
EXPECT_EQ(array.At(2), nullptr);
}

TEST(TObjArrayTest, AddFirstAndLast)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");

array.AddFirst(s1);
array.AddLast(s2);

EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), s2);
}

TEST(TObjArrayTest, AddAt)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");

array.AddAt(s1, 0);
array.AddAt(s2, 2);

EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.GetLast(), 2);

EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), nullptr);
EXPECT_EQ(array.At(2), s2);
}

TEST(TObjArrayTest, AddAtAndExpand)
{
TObjArray array(2);
array.SetOwner(kTRUE);

auto *s1 = new TNamed("element", "");

array.AddAtAndExpand(s1, 5);

EXPECT_EQ(array.GetEntries(), 1);
EXPECT_EQ(array.GetLast(), 5);
EXPECT_EQ(array.At(5), s1);
}

TEST(TObjArrayTest, AddAtFree)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");
auto *s3 = new TNamed("third", "");

array.AddAt(s1, 0);
array.AddAt(s2, 2);

Int_t idx = array.AddAtFree(s3);
EXPECT_EQ(idx, 1);
EXPECT_EQ(array.At(1), s3);
EXPECT_EQ(array.GetEntries(), 3);
}

TEST(TObjArrayTest, AddBeforeAndAfter)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s2 = new TNamed("second", "");
array.AddAt(s2, 2);

auto *s1 = new TNamed("first", "");
array.AddBefore(s2, s1);

auto *s3 = new TNamed("third", "");
array.AddAfter(s2, s3);

EXPECT_EQ(array.GetEntries(), 3);
EXPECT_EQ(array.At(1), s1);
EXPECT_EQ(array.At(2), s2);
EXPECT_EQ(array.At(3), s3);
}

TEST(TObjArrayTest, Remove)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");
auto *s3 = new TNamed("third", "");

array.Add(s1);
array.Add(s2);
array.Add(s3);

TObject *removed = array.Remove(s2);
EXPECT_EQ(removed, s2);
EXPECT_EQ(array.GetEntries(), 2);

EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), nullptr);
EXPECT_EQ(array.At(2), s3);

delete removed;
}

TEST(TObjArrayTest, RemoveAt)
{
// Test removing middle element
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");
auto *s3 = new TNamed("third", "");

array.Add(s1);
array.Add(s2);
array.Add(s3);
EXPECT_EQ(array.GetLast(), 2);

TObject *removed = array.RemoveAt(1);
EXPECT_EQ(removed, s2);
EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), nullptr);
EXPECT_EQ(array.At(2), s3);
EXPECT_EQ(array.GetLast(), 2);

delete removed;
}

// Test removing last element updates GetLast()
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");
auto *s3 = new TNamed("third", "");

array.Add(s1);
array.Add(s2);
array.Add(s3);
EXPECT_EQ(array.GetLast(), 2);

TObject *removed = array.RemoveAt(2);
EXPECT_EQ(removed, s3);
EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), s2);
EXPECT_EQ(array.At(2), nullptr);
EXPECT_EQ(array.GetLast(), 1);

delete removed;
}
}

TEST(TObjArrayTest, Compress)
{
TObjArray array;
array.SetOwner(kTRUE);

auto *s1 = new TNamed("first", "");
auto *s2 = new TNamed("second", "");
auto *s3 = new TNamed("third", "");

array.Add(s1);
array.Add(s2);
array.Add(s3);

// Remove the middle element, creating a gap: [s1, nullptr, s3]
TObject *removed = array.RemoveAt(1);
delete removed;

EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), nullptr);
EXPECT_EQ(array.At(2), s3);
EXPECT_EQ(array.GetLast(), 2);

// Compress closes the gap: [s1, s3, nullptr]
array.Compress();

EXPECT_EQ(array.GetEntries(), 2);
EXPECT_EQ(array.At(0), s1);
EXPECT_EQ(array.At(1), s3);
EXPECT_EQ(array.At(2), nullptr);
EXPECT_EQ(array.GetLast(), 1);
}

TEST(TObjArrayTest, ClearAndDelete)
Comment thread
pcanal marked this conversation as resolved.
{
TrackObject::fgCount = 0;

// 1. Non-owner Clear(): removes pointers but does NOT delete objects
{
TObjArray array;
array.SetOwner(kFALSE);

auto *o1 = new TrackObject();
auto *o2 = new TrackObject();
array.Add(o1);
array.Add(o2);

EXPECT_EQ(TrackObject::fgCount, 2);
EXPECT_EQ(array.GetEntries(), 2);

array.Clear();
EXPECT_EQ(array.GetEntries(), 0);
EXPECT_EQ(TrackObject::fgCount, 2);

delete o1;
delete o2;
EXPECT_EQ(TrackObject::fgCount, 0);
}

// 2. Non-owner Delete(): explicitly deletes all heap objects
{
TObjArray array;
array.SetOwner(kFALSE);

array.Add(new TrackObject());
array.Add(new TrackObject());

EXPECT_EQ(TrackObject::fgCount, 2);
EXPECT_EQ(array.GetEntries(), 2);

array.Delete();
EXPECT_EQ(array.GetEntries(), 0);
EXPECT_EQ(TrackObject::fgCount, 0);
}

// 3. Owner Clear(): delegates to Delete(), deleting all objects
{
TObjArray array;
array.SetOwner(kTRUE);

array.Add(new TrackObject());
array.Add(new TrackObject());

EXPECT_EQ(TrackObject::fgCount, 2);
EXPECT_EQ(array.GetEntries(), 2);

array.Clear();
EXPECT_EQ(array.GetEntries(), 0);
EXPECT_EQ(TrackObject::fgCount, 0);
}
}

TEST(TObjArrayTest, Iteration)
{
TObjArray array;
array.SetOwner(kTRUE);

array.Add(new TNamed("A", ""));
array.Add(new TNamed("B", ""));
array.Add(new TNamed("C", ""));

Int_t count = 0;
TIter next(&array);
TObject *obj;
while ((obj = next())) {
count++;
}

EXPECT_EQ(count, 3);
}
Loading