⛏️ index : haiku.git

/*
 * Copyright 2018, Sean Healy
 * Distributed under the terms of the MIT License.
 */



#include "common.h"

#include <Application.h>
#include <Window.h>
#include <TestUtils.h>


#include <OutlineListView.h>

BListItem* gExpected[16];
int gIndex = 0;
int gCount = 0;


template<>
struct CppUnit::assertion_traits<BListItem*>
{
	static bool equal(const BListItem* x, const BListItem* y) {
		return x == y;
	}

	static string toString(const BListItem* x) {
		if (x == NULL)
			return "(null)";
		return ((BStringItem*)x)->Text();
	}
};


BListItem*
CheckExpected(BListItem* item, void* arg)
{
	BStringItem* str = (BStringItem*)item;
	fprintf(stderr, "Item @%d: %s\n", gIndex, str == NULL ? "(null)" : str->Text());

	CHK(gIndex < gCount);
	CPPUNIT_ASSERT_EQUAL(gExpected[gIndex], item);
	gIndex++;
	return NULL;
}


BListItem*
FillExpected(BListItem* item, void* arg)
{
	gExpected[gCount] = item;
	gCount++;
	return NULL;
}


void
CheckItemsUnder(BOutlineListView* view, BListItem* superitem, bool oneLevelOnly)
{
	for (int i = 0; i < gCount; i++)
		CPPUNIT_ASSERT_EQUAL(gExpected[i], view->ItemUnderAt(superitem, oneLevelOnly, i));

	// Check that we don't get more items
	CPPUNIT_ASSERT_EQUAL((BListItem*)NULL, view->ItemUnderAt(superitem, oneLevelOnly, gCount));
}


class OutlineListViewTest: public TestCase
{
	public:
		OutlineListViewTest() {}
		OutlineListViewTest(std::string name) : TestCase(name) {}

		void EachItemUnder();
		void AddUnder();
		void ItemUnderAt();

		static Test* Suite();

	private:
		static BOutlineListView* _SetupTest(const char* name);
};


void
OutlineListViewTest::EachItemUnder()
{
	BOutlineListView* view = _SetupTest("OutlineListView_EachItemUnder");

	// First test is easy
	gExpected[0] = view->FullListItemAt(6);
	gExpected[1] = view->FullListItemAt(8);
	gExpected[2] = view->FullListItemAt(9);
	gCount = 3;
	gIndex = 0;

	fprintf(stderr, "Easy test\n");
	view->EachItemUnder(view->FullListItemAt(5), true, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(view->FullListItemAt(5), true));

	// Check that collapsing an item does not change the outcome
	gIndex = 0;
	view->Collapse(view->FullListItemAt(0));

	fprintf(stderr, "One collapsed\n");
	view->EachItemUnder(view->FullListItemAt(5), true, CheckExpected, NULL);

	gIndex = 0;
	view->Collapse(view->FullListItemAt(5));

	fprintf(stderr, "Two collapsed\n");
	view->EachItemUnder(view->FullListItemAt(5), true, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(view->FullListItemAt(5), true));

	// Also check deeper levels
	gExpected[1] = view->FullListItemAt(7);
	gExpected[2] = view->FullListItemAt(8);
	gExpected[3] = view->FullListItemAt(9);
	gCount = 4;
	gIndex = 0;

	fprintf(stderr, "All levels\n");
	view->EachItemUnder(view->FullListItemAt(5), false, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(view->FullListItemAt(5), false));

	view->Expand(view->FullListItemAt(5));
	view->Collapse(view->FullListItemAt(6));
	gIndex = 0;

	fprintf(stderr, "All levels with a collapsed sublevel\n");
	view->EachItemUnder(view->FullListItemAt(5), false, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(view->FullListItemAt(5), false));

	// NULL is the parent of level 0 items
	gExpected[0] = view->FullListItemAt(0);
	gExpected[1] = view->FullListItemAt(5);
	gExpected[2] = view->FullListItemAt(10);
	gCount = 3;
	gIndex = 0;

	fprintf(stderr, "Level 0\n");
	view->EachItemUnder(NULL, true, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(NULL, true));

	// No visits when the item is not in the list
	BListItem* notfound = new BStringItem("Not found");
	gCount = 0;
	gIndex = 0;

	fprintf(stderr, "Item not in the list\n");
	view->EachItemUnder(notfound, true, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(notfound, true));
	view->EachItemUnder(notfound, false, CheckExpected, NULL);
	CPPUNIT_ASSERT_EQUAL(gCount, view->CountItemsUnder(notfound, false));

	// Don't actually run anything
	delete view->Window();
}


void
OutlineListViewTest::AddUnder()
{
	BOutlineListView* view = _SetupTest("OutlineListView_AddUnder");

	BListItem* one = view->FullListItemAt(0);
	BListItem* oneA = view->FullListItemAt(1);
	BListItem* oneA0 = new BStringItem("One-A-0");
	BListItem* oneA1 = view->FullListItemAt(2);

	int32 count = view->FullListCountItems();

	BListItem* last = view->FullListItemAt(count - 1);
	BListItem* newLast = new BStringItem("NewLast");

	view->AddUnder(newLast, NULL);
	view->AddUnder(oneA0, oneA);

	fprintf(stderr, "Count\n");
	CPPUNIT_ASSERT_EQUAL(count + 2, view->FullListCountItems());

	fprintf(stderr, "Insertion order\n");
	CPPUNIT_ASSERT_EQUAL(one, view->FullListItemAt(0));
	CPPUNIT_ASSERT_EQUAL(oneA, view->FullListItemAt(1));
	CPPUNIT_ASSERT_EQUAL(oneA0, view->FullListItemAt(2));
	CPPUNIT_ASSERT_EQUAL(oneA1, view->FullListItemAt(3));
	CPPUNIT_ASSERT_EQUAL(last, view->FullListItemAt(count));
	CPPUNIT_ASSERT_EQUAL(newLast, view->FullListItemAt(count + 1));

	fprintf(stderr, "Levels\n");
	CPPUNIT_ASSERT_EQUAL(0, one->OutlineLevel());
	CPPUNIT_ASSERT_EQUAL(1, oneA->OutlineLevel());
	CPPUNIT_ASSERT_EQUAL(2, oneA0->OutlineLevel());
	CPPUNIT_ASSERT_EQUAL(2, oneA1->OutlineLevel());
	CPPUNIT_ASSERT_EQUAL(0, newLast->OutlineLevel());

	// Don't actually run anything
	delete view->Window();
}


void
OutlineListViewTest::ItemUnderAt()
{
	BOutlineListView* view = _SetupTest("OutlineListView_ItemUnderAt");

	// EachItemUnder has already been checked, we can use it to know what to expect
	gCount = 0;
	view->EachItemUnder(view->FullListItemAt(5), true, FillExpected, NULL);

	fprintf(stderr, "Easy test\n");
	CheckItemsUnder(view, view->FullListItemAt(5), true);

	// Check that collapsing an item does not change the outcome
	view->Collapse(view->FullListItemAt(0));

	fprintf(stderr, "One collapsed\n");
	CheckItemsUnder(view, view->FullListItemAt(5), true);

	view->Collapse(view->FullListItemAt(5));

	fprintf(stderr, "Two collapsed\n");
	CheckItemsUnder(view, view->FullListItemAt(5), true);

	// Also check deeper levels
	gCount = 0;
	view->EachItemUnder(view->FullListItemAt(5), false, FillExpected, NULL);

	fprintf(stderr, "All levels\n");
	CheckItemsUnder(view, view->FullListItemAt(5), false);

	view->Expand(view->FullListItemAt(5));
	view->Collapse(view->FullListItemAt(6));

	fprintf(stderr, "All levels with a collapsed sublevel\n");
	CheckItemsUnder(view, view->FullListItemAt(5), false);

	// NULL is the parent of level 0 items
	gCount = 0;
	view->EachItemUnder(NULL, true, FillExpected, NULL);

	fprintf(stderr, "Level 0\n");
	CheckItemsUnder(view, NULL, true);

	// Get NULL when the item is not in the list
	BListItem* notfound = new BStringItem("Not found");
	fprintf(stderr, "Item not in the list\n");
	CPPUNIT_ASSERT_EQUAL((BListItem*)NULL, view->ItemUnderAt(notfound, true, 0));
	CPPUNIT_ASSERT_EQUAL((BListItem*)NULL, view->ItemUnderAt(notfound, false, 0));

	// Don't actually run anything
	delete view->Window();
}


Test*
OutlineListViewTest::Suite()
{
	TestSuite* SuiteOfTests = new TestSuite;

	ADD_TEST4(BOutlineListView, SuiteOfTests, OutlineListViewTest, EachItemUnder);
	ADD_TEST4(BOutlineListView, SuiteOfTests, OutlineListViewTest, AddUnder);
	ADD_TEST4(BOutlineListView, SuiteOfTests, OutlineListViewTest, ItemUnderAt);

	return SuiteOfTests;
}


BOutlineListView*
OutlineListViewTest::_SetupTest(const char* name)
{
	if (be_app == NULL)
		new BApplication("application/x-vnd.OutlineListView.test");

	BWindow* window = new BWindow(BRect(50, 50, 550, 550), name,
		B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE, 0);

	BOutlineListView* view = new BOutlineListView(BRect(5, 5, 495, 495), "View",
		B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL);
	window->AddChild(view);

	view->AddItem(new BStringItem("One", 0));
	view->AddItem(new BStringItem("One-A", 1));
	view->AddItem(new BStringItem("One-A-1", 2));
	view->AddItem(new BStringItem("One-B", 1));
	view->AddItem(new BStringItem("One-C", 1));

	view->AddItem(new BStringItem("Two", 0));
	view->AddItem(new BStringItem("Two-A", 1));
	view->AddItem(new BStringItem("Two-A-1", 2));
	view->AddItem(new BStringItem("Two-B", 1));
	view->AddItem(new BStringItem("Two-C", 1));

	view->AddItem(new BStringItem("Three", 0));
	view->AddItem(new BStringItem("Three-A", 1));
	view->AddItem(new BStringItem("Three-A-1", 2));
	view->AddItem(new BStringItem("Three-B", 1));
	view->AddItem(new BStringItem("Three-C", 1));

	return view;
}


CppUnit::Test* OutlineListViewTestSuite()
{
	CppUnit::TestSuite* testSuite = new CppUnit::TestSuite();

	testSuite->addTest(OutlineListViewTest::Suite());

	return testSuite;
}